How to localize perl package (tar.gz) - perl

Let's say I have myscript.tar.gz package generated by h2xs -AX myscript containing bin/myScript.pl and lib/MyPackage/MyModule.pm. Makefile.PL and MANIFEST manualy edited so I'm able to install the package and run myScript.pl.
myscript.pl:
#!/usr/bin/perl
use strict;
use warnings;
use MyPackage::MyModule;
my $generator = MyPackage::MyModule->new();
my $value = $generator->getValue();
#And the message to be translated/localized
print "Obtained value was $value";
How do I localize my package?
I read this: How can I add internationalization to my Perl script? and alike, but it's sort of outdated. I also tried example from libintrl-perl, but I'm not wise from it and couldn't make it work.

Thanks to #Håkon:
Solution: Dist:Zilla - instead of h2xs approach.
In case of using Debian these packages are neccessary: libdist-zilla-perl libdist-zilla-localetextdomain-perl libdist-zilla-plugin-localemsgfmt-perl
First start with dzil init
$ dzil setup
Next create a new package:
$ dzil new myscript
then basically follow Dist::Zilla::LocaleTextDomain and
use this in a script/module to be translated:
use Locale::TextDomain "myscript";
#and format strings like this:
print __ "Obtaining value...";
print __x("Obtained value was {value}", value => $value);
add this to dist.ini:
[LocaleTextDomain]
textdomain = myscript
scan for messages/strings to be translated:
$ dzil msg-scan
initialize language translation files:
$ dzil msg-init en us ...
translate *.po files in po/ directory
possibly test:
$ dzil msg-compile po/en.po
$ LANGUAGE=en perl -Ilib -CAS -I. bin/myScript.pl
and remove language test dir after
$ rm LocaleData/ -r
now just create package:
$dzil release
and enjoy the beautiful .tar.gz package.
During the release process Dist::Zilla offers to upload the module to PAUSE, but defaults to not to upload (still figuring out how to prevent the offer).
It's actually more convenient - no MANIFEST to include files just throw them to lib/ and bin/- It's magic! :)
I hope someone else will find this usefull too.

Related

Specify shebang on project using Perl Module::Build

I'm packaging clusterssh to openSUSE and need to change default shebang from #!/usr/bin/env perl to #!/usr/bin/perl. clusterssh uses Module::Build.
I'll probably use the patch (as Debian package do), but I wonder easy usage for fix_shebang_line(#files) in RPM packaging.
It's already called during the building process.
Basically, uninstalled scripts should use #!/usr/bin/perl or #!perl, and the installation process should rewrite that to the point to the perl used to run the installer. That way, a script installed by /usr/bin/perl will use /usr/bin/perl, and a script installed using /home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl will use /home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl.
(This applies to both the Module::Build installer and the ExtUtils::MakeMaker installer.)
Note that the documentation for fix_shebang_line says it doesn't touch a shebang line of #!/usr/bin/env perl (because it's not recognized as invocation of perl), so simply patching the scripts to use #!/usr/bin/perl instead of #!/usr/bin/env perl does the trick.
With that change, the install-ready staging directory (blib) produced by ./Build will contain the edited files.
$ perl -e'CORE::say $^X'
/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
$ for fn in ccon crsh csftp cssh ctel; do printf '%-6s ' "$fn:"; head -n 1 "bin_PL/$fn"; done
ccon: #!/usr/bin/perl
crsh: #!/usr/bin/perl
csftp: #!/usr/bin/perl
cssh: #!/usr/bin/perl
ctel: #!/usr/bin/perl
$ perl Build.PL
Could not get valid metadata. Error is: ERROR: Missing required field 'dist_abstract' for metafile
Could not create MYMETA files
Creating new 'Build' script for 'App-ClusterSSH' version 'v4.13.203'
$ ./Build
Building App-ClusterSSH
Using perl binary: /home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
Using perl version v5.26.2
Generating: /home/ikegami/tmp/clusterssh/bin_PL/cssh
Generating: /home/ikegami/tmp/clusterssh/bin_PL/csftp
Generating: /home/ikegami/tmp/clusterssh/bin_PL/ccon
Generating: /home/ikegami/tmp/clusterssh/bin_PL/crsh
Generating: /home/ikegami/tmp/clusterssh/bin_PL/ctel
Generating: /home/ikegami/tmp/clusterssh/bin_PL/clusterssh_bash_completion.dist
$ for fn in ccon crsh csftp cssh ctel; do printf '%-6s ' "$fn:"; head -n 1 "blib/script/$fn"; done
ccon: #!/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
crsh: #!/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
csftp: #!/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
cssh: #!/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
ctel: #!/home/ikegami/usr/perlbrew/perls/5.26.2t/bin/perl
I didn't bother running ./Build install, whose main task is to copy the files from the staging directory into their final locations. Besides, that part will need to be replaced by your package manager anyway (assuming you're simply placing the contents of the blib directory into your package).
If you somehow need to do it yourself, you could use the following:
find bin -type f \
-exec perl -i -pe'
s/^#!\S*perl\S*/#!$^X/ if $. == 1;
close ARGV if eof;
' {} +
Notes:
Use the perl you wish the scripts to use.
GNU tools assumed; adjust as necessary.
close ARGV if eof; resets the line number ($.) for each file.
eof is different than eof(), and only the former will work here.
The line breaks are optional and may be removed.

use perlbrew with dist zilla test

I am using the Dist::Zilla module to release and test my module. I am also using Perlbrew. When I run a script using perlbrew that includes my module, the script runs fine:
use strict;
use My::Module;
However, whenever I run dzil test, on a test that just tries to include my module:
#!perl -T
use strict;
use warnings FATAL => 'all';
use Test::More;
plan tests => 1;
BEGIN {
use_ok( 'My::Module' ) || print "Bail out!\n";
}
diag( "Testing My::Module $My::Module::VERSION, Perl $], $^X" );
It fails with this error saying that it can't find the module Mouse (which my module includes):
Error: Can't locate Mouse.pm in #INC (you may need to install the Mouse module) (#INC contains:
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/lib
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/arch
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18
/Network/Library/Perl/5.18/darwin-thread-multi-2level
/Network/Library/Perl/5.18
/Library/Perl/Updates/5.18.2/darwin-thread-multi-2level
/Library/Perl/Updates/5.18.2
/System/Library/Perl/5.18/darwin-thread-multi-2level
/System/Library/Perl/5.18
/System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.18) at
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/lib/My/Module.pm line 4.
It says that it cannot find Mouse.pm, which I know is located at
/Users/user/perl5/lib/perl5/darwin-2level
I see that for some reason that directory is not located in #INC, which is interesting because if I run this command to print out all the directories in #INC:
perl -e 'print "$_\n" for #INC'
I get:
/Users/user/perl5/lib/perl5/darwin-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/darwin-2level
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0/darwin-2level
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0
.
So when I run perl on the command line then the darwin-2level directory is present in #INC, but whenever I run dzil test it is not. This might not have much to do with Dist::Zilla, since I think Dist::Zilla just creates Makefile.PL and runs make test for you. Could this be because for testing an older version of perl is being required? Like so:
use 5.006;
But even so, some Perlbrew directories are present in #INC during the test such as
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
Does anyone know how I can make it so I can use the Mouse installation in my perl directory instead of installing a systemwide one? I had a previous error with another module that couldn't be found when I ran dzil test, and that module was in the same directory as Mouse. I was able to fix the issue by installing the module systemwide instead of locally in my home perl5 directory, but I'd prefer to use the Mouse installed by Perlbrew and not mess with my system perl if possible. I am using Perlbrew version 0.73.
You're trying to install it using the wrong perl since you're using dzil installed by a different perl than the one you want to use.
Furthermore, you shouldn't see any of the following in your perlbrewed perl's #INC:
/Users/user/perl5/lib/perl5/darwin-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/ (You perlbrewed perl isn't even threaded!!!)
Let's clean up your environment.
Unset env vars PERL5LIB, PERLLIB, PERL5OPT, PERL_MM_OPT and PERL_MB_OPT. Permanently. Get rid of them in your login scripts, then unset them from the current shell or log back in. (Make a note of what they were as a backup.)
Clear cpan's configuration item makepl_arg. From within cpan,
o conf makepl_arg # Just to see its current value as a backup.
o conf makepl_arg ''
o conf commit
In particular, we want to remove anything that indicates an installation path, including INSTALL_BASE, PREFIX and LIB.
Clear cpan's configuration item mbuildpl_arg. From within cpan,
o conf mbuildpl_arg # Just to see its current value as a backup.
o conf mbuildpl_arg ''
o conf commit
In particular, we want to remove anything that indicates an installation path, including --install_base, --prefix and --lib.
Since you're there, do the following from within cpan:
o conf build_dir_reuse 0
o conf commit
This will restore the setting to its default, which will save you headaches if it was changed.
Install the dependencies.
cpan Dist::Zilla Mouse
At this point, executing which dzil should give
/Users/user/perl5/perlbrew/perls/perl-5.16.0/bin/dzil
If so, you should be good to go.
If not, do hash -r and try which dzil again. (This shouldn't be needed, but just to be sure.)
If still not, provide the output of the following commands:
echo "$PATH"
which cpan
head -n 3 "$( which cpan )"
echo 'o conf' | cpan | grep arg
which dzil
head -n 3 "$( which dzil )"
perl -V # Uppercase "V"

Where are perl modules located in archlinux

Im trying to find perl modules, such as strict and warnings, but i cant find them... btw im actually using archlinux, i tried using
whereis
but it throws nothing.
If the module has POD documentation embedded (which most do), the following will display its location:
perldoc -l Some::Module (Lowercase "L" for "location")
Otherwise, you can use
perl -E'use Some::Module; say $INC{"Some/Module.pm"};'
You might be interested in identifying all the locations in which your Perl searches for modules. If so, look at the contents of #INC. You can use
perl -V (Uppercase "V")
or
perl -E'say for #INC;'
You may also be interested in Devel::Modlist. The following will lists the path to all the modules used (directly or indirectly) by a script or module:
perl -d:Modlist=path some_script.pl
perl -d:Modlist=path -e'use Some::Module;'
Without =path, it returns the versions of all the modules.
To find an individual module:
perldoc -l warnings
All modules are under #INC directories:
perl -V
See also: Find installed Perl modules matching a regular expression
The %INC hash holds the on-disk locations of loaded modules, keyed by the package name. You can step through the keys of %INC and print out the associated value. For example:
$ perl -MData::Dump -e 'print "$_: $INC{$_}\n" foreach keys %INC'
(I loaded Data::Dump so that at least one module would be pulled in for sure. You don't have to load that specific module yourself.)
Also, the #INC array holds the include paths that perl searches for modules in, so you can always do:
$ perl -E 'say foreach #INC'
To find all the default include paths.
Since you are using a Linux distribution, the native package manager is the most suitable tool. In this case, it's highly recommend to use pacman for such a task:
pacman -Ql perl | egrep '(strict|warnings).pm'

How can I find out where a Perl module is installed?

How do get the path of a installed Perl module by name,
e.g. Time::HiRes?
I want this just because I have to run my perl script on different nodes of a SGE Grid Engine system. Sometimes, even run as other username.
I can use CPAN.pm to install packages for myself, but it is not so easy to install for other users without chmod 666 on folders.
perl -MTime::HiRes -e 'print $INC{"Time/HiRes.pm"}' or perldoc -l Time::HiRes
Mostly I use perldoc to get a location:
$ perldoc -l Module
You can also get module details with the cpan tool that comes with Perl:
$ cpan -D Time::HiRes
Time::HiRes
-------------------------------------------------------------------------
High resolution time, sleep, and alarm
J/JH/JHI/Time-HiRes-1.9719.tar.gz
/usr/local/perls/perl-5.10.0/lib/5.10.0/darwin-2level/Time/HiRes.pm
Installed: 1.9711
CPAN: 1.9719 Not up to date
Andrew Main (Zefram) (ZEFRAM)
zefram#fysh.org
It even works on modules that you haven't installed:
$ cpan -D Win32::Process
Win32::Process
-------------------------------------------------------------------------
Interface to Win32 Process functions
J/JD/JDB/Win32-Process-0.14.tar.gz
Installed:
CPAN: 0.14 Not up to date
Jan Dubois (JDB)
jand#activestate.com
I think maybe I need an XML option like svn.
Note: This solution proposes use of a (self-authored) utility that you must download. While it offers what I believe to be helpful features, installing a third-party solution first is not an option for everyone.
I've created whichpm, a cross-platform CLI (Linux, macOS, Window) that locates installed Perl modules by module (package) name, and optionally reports information about them, including detection of accidental duplicates.
Examples
# Locate the Data::Dumper module.
$ whichpm Data::Dumper
/usr/lib/perl/5.18/Data/Dumper.pm
# Locate the Data::Dumper module, and also print
# version information and core-module status.
$ whichpm -v Data::Dumper
Data::Dumper 2.145 core>=5.005 /usr/lib/perl/5.18/Data/Dumper.pm
# Locate the Data::Dumper module and open it in your system's default text
# editor.
$ whichpm -e Data::Dumper
# Look for accidental duplicates of the Foo::Bar module.
# Normally, only 1 path should be returned.
$ whichpm -a Foo::Bar
/usr/lib/perl/5.18/Foo/Bar.pm
./Foo/Bar.pm
# Print the paths of all installed modules.
$ whichpm -a
Installation
Prerequisites: Linux, macOS, or Windows, with Perl v5.4.50 or higher installed.
Installation from the npm registry
With Node.js or io.js installed, install the package as follows:
[sudo] npm install whichpm -g
Manual installation (macOS and Linux)
Download the CLI as whichpm.
Make it executable with chmod +x whichpm.
Move it or symlink it to a folder in your $PATH, such as /usr/local/bin (OSX) or /usr/bin (Linux).
If need to find which modules are actually used by your script you can use perl debuggers M command:
[ivan#server ~]$ perl -d your_script.pl
...
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB M
'AutoLoader.pm' => '5.60 from /usr/lib/perl5/5.8.8/AutoLoader.pm'
'Carp.pm' => '1.04 from /usr/lib/perl5/5.8.8/Carp.pm'
...
This will help in case when you have modules with same names but in different folder.
I just find another one:
http://www.perlmonks.org/?node_id=568730
#!/bin/sh
echo 'print map { sprintf( "%20s : %s\n", $_, $INC{$_} ) } sort keys %INC; print "\n'$1' version : $'$1'::VERSION\n\n"' | perl "-M$1"
the script just print out everything in %INC when you run perl -MSTH::STH
eg:
$ whichpm CGI
CGI.pm : /System/Library/Perl/5.8.6/CGI.pm
CGI/Util.pm : /System/Library/Perl/5.8.6/CGI/Util.pm
Carp.pm : /System/Library/Perl/5.8.6/Carp.pm
Exporter.pm : /System/Library/Perl/5.8.6/Exporter.pm
constant.pm : /System/Library/Perl/5.8.6/constant.pm
overload.pm : /System/Library/Perl/5.8.6/overload.pm
strict.pm : /System/Library/Perl/5.8.6/strict.pm
vars.pm : /System/Library/Perl/5.8.6/vars.pm
warnings.pm : /System/Library/Perl/5.8.6/warnings.pm warnings/register.pm : /System/Library/Perl/5.8.6/warnings/register.pm
CGI version : 3.05
I like to use the V module.
Just install it from CPAN or by installing the package libv-perl on Debian or Ubuntu.
Then use it like this:
$ perl -MV=DBI
DBI
/Users/michiel/.plenv/versions/5.24.0/lib/perl5/site_perl/5.24.0/darwin-2level/DBI.pm: 1.636
Other output example:
$ perl -MV=Time::HiRes
Time::HiRes
/usr/lib/perl/5.18/Time/HiRes.pm: 1.9725
It seems like the simplest way is perldoc -l Time::HiRes.
If that isn't available for some reason, here's a pragmatic solution:
Step 1: Instantiate the module in your script...
#! /usr/bin/perl -w
use Time::HiRes();
new Time::HiRes();
Step 2: Execute the script with the Perl graphical debugger...
export PERL5LIB=$PERL5LIB:~/perl ## tell perl where to look for "Devel"/"ptkdb.pm"
perl -d:ptkdb (yourscript.pl)
Step 3: Step in to the new call.
The full pathname of the module will be displayed on the title-bar of the debugger window.
Another approach that might be useful would be to search all of the folders in $PERL5LIB.
Perldoc -l works for me
perldoc -l "File::Find"
/opt/perl_32/lib/5.8.8/File/Find.pm
To expand on #Ivan's answer that allows this to be run without installing additional software the following will use Perl's debugger to find a specific module (or modules):
perl -de 'use <Module Name>;'
For Example:
perl -de 'use DBD::Oracle;'
Output:
Loading DB routines from perl5db.pl version 1.37
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
DBD::Oracle::CODE(0x27f81d8)(/usr/local/lib64/perl5/DBD/Oracle.pm:113):
113: $ENV{PERL_BADFREE} = 0;
DB<1> q
In OSX you can use:
perl -e 'print join("\n",#INC)'
The result should be the location of your lib.
Then add this code in your Perl code:
use lib '/your/folder/location/to/lib';

How can I find the version of an installed Perl module?

How do you find the version of an installed Perl module?
This is in an answer down at the bottom, but I figure it important enough to live up here. With these suggestions, I create a function in my .bashrc
function perlmodver {
perl -M$1 -e 'print "Version " . $ARGV[0]->VERSION . " of " . $ARGV[0] . \
" is installed.\n"' $1
}
Most modules (especially ones from The CPAN) have a $VERSION variable:
perl -MSome::Module -le 'print $Some::Module::VERSION'
Why are you trying to get the version of the module? Do you need this from within a program, do you just need the number to pass to another operation, or are you just trying to find out what you have?
I have this built into the cpan (which comes with perl) with the -D switch so you can see the version that you have installed and the current version on CPAN:
$ cpan -D Text::CSV_XS
Text::CSV_XS
-------------------------------------------------------------------------
Fast 8bit clean version of Text::CSV
H/HM/HMBRAND/Text-CSV_XS-0.54.tgz
/usr/local/lib/perl5/site_perl/5.8.8/darwin-2level/Text/CSV_XS.pm
Installed: 0.32
CPAN: 0.54 Not up to date
H.Merijn Brand (HMBRAND)
h.m.brand#xs4all.nl
If you want to see all of the out-of-date modules, use the -O (capital O) switch:
$ cpan -O
Module Name Local CPAN
-------------------------------------------------------------------------
Apache::DB 0.1300 0.1400
Apache::SOAP 0.0000 0.7100
Apache::Session 1.8300 1.8700
Apache::SizeLimit 0.0300 0.9100
Apache::XMLRPC::Lite 0.0000 0.7100
... and so on
If you want to see this for all modules you have installed, try the -a switch to create an autobundle.
VERSION is a UNIVERSAL method of all Perl classes. You can use it to get the module version (if it has been set which it usually has).
Here is a one liner where you only have to add the module name once:
perl -le 'eval "require $ARGV[0]" and print $ARGV[0]->VERSION' Some::Module
There is a less-typing trick, that works provided your module doesn't have something insane like a Unix timestamp as a version number.
perl -MFoo::Bar\ 9999
This works because what it translates to is
use Foo::Bar 9999;
i.e. a version of Foo::Bar that's at least version 9999 or newer.
And what you get is
Foo::Bar version 9999 required--this is only version 1.1.
BEGIN failed--compilation aborted.
(Neat trick I learned from Matt Trout.)
If you are lucky, the module will have a package variable named $VERSION:
$ perl -MCPAN -e 'print "$CPAN::VERSION\n"'
1.9205
This is needed for modules to be distributed on CPAN, but internally developed modules might follow a different convention or none at all.
Thanks for the answers! I've created a function in my .bashrc to easily find the version of a Perl module:
function perlmodver {
perl -M$1 -e 'print $ARGV[0]->VERSION . "\n"' $1
}
Easiest to remember and most robust version for me:
perl -e 'use Search::Elasticsearch; print $Search::Elasticsearch::VERSION;'
Check out the pmtools scripts on CPAN. If you're using a Debian(-based) distro, there's also a handy pmtools package. This includes a script "pmvers" that tells you a module's version. It's quite handy.
It does something similar to the various one-liners folks posted, but it's a bit smarter about error handling, and can give you the version of more than one module at once.
I wrote a small script to report that: perlver.
This is a simple little tool that
tells you what version of a module you
have installed, and where the .pm file
is located. It also ensures the module
can be loaded successfully. It
automatically converts ‘-’, ‘/’, or
‘\’ to ‘::’, so you can use a pathname
or distribution name instead of the
canonical module name.
It assumes that the module defines a $VERSION. If the module doesn't define a $VERSION, it will still tell you where the .pm file is, so you can examine it manually. You can also check several modules at once:
$ perlver CPAN DBD-Pg Getopt::Long
CPAN 1.7602 is
/usr/lib/perl5/5.8.8/CPAN.pm
DBD::Pg 1.49 is
/usr/lib/perl5/vendor_perl/5.8.8/i686-linux/DBD/Pg.pm
Getopt::Long 2.36 is
/usr/lib/perl5/vendor_perl/5.8.8/Getopt/Long.pm
In addition, for modules that use Exporter.pm, you can get this information with this trick:
perl -MSome::Module=99999 -ex
Some::Module version 99999 required--this is only version 1.9205 at ...
For modules that don't use Exporter.pm, a slightly longer trick reports the same information:
perl -e'use Some::Module 99999'
Some::Module version 99999 required--this is only version 1.9205 at ...
We have the system perl (/usr/bin/perl) in Solaris 10, and above solutions are useless. Some of them report "module.pm is not installed", some of them have no output.
Here is the code which is helpful, which can list all modules and their version.
#!/usr/bin/perl
use strict;
use ExtUtils::Installed;
my #modules;
my $installed = ExtUtils::Installed->new();
if (scalar(#ARGV) > 0) {
#modules = #ARGV;
} else {
#modules = $installed->modules();
}
print "Module\tVersion\n";
foreach (#modules) {
print $_ . "\t" . $installed->version($_) . "\n";
}
You can also take a look at App::module::version
$ module-version
The version of App::module::version in /home/yourself/perl5/lib/perl5 is 1.004