#!/usr/bin/perl use strict; use warnings; our $VERSION = '1.02'; # Removing this dependency # use Text::Trim qw( trim ); use List::Util qw( max ); use Module::Util qw( :all ); use Pod::Usage; use Getopt::Long qw( :config posix_default bundling ); =head1 NAME pm_which - find installed modules =head1 SYNOPSIS pm_which [ options ] module(s) Returns the path to the given module(s) =head2 OPTIONS -q, --quiet Just print paths -p, --paths Just convert the module name into a relative path -a, --all Print all paths, not just the first one found -n, --namespace Print all modules in the given namespace -m Only print module names, not paths -V Show module version -I libpath Add a path to search (like perl -I) -d, --dump Dump paths that would be searched (@INC by default) -h, --help Print this message -v, --version Print version information - Read modules from stdin, one per line =cut our($quiet, $all, $namespace, $name_only, $paths, $dump, $stdin, $version); our @search = @INC; GetOptions( 'q|quiet' => \$quiet, 'a|all' => \$all, 'p|paths' => \$paths, 'd|dump' => \$dump, 'n|namespace' => \$namespace, 'm' => \$name_only, 'V' => \$version, '' => \$stdin, 'h|help' => sub { pod2usage(-exitval => 0) }, 'I=s' => sub { unshift @search, $_[1] }, 'v|version' => \&version, ) or pod2usage( -exitval => 1 ); if ($dump) { print join("\n", @search), "\n"; exit 0; } require ExtUtils::MakeMaker if $version; our @modules = @ARGV; # Also read module names from STDIN if we have '-' switch # Removing Text::Trim dependency # push @modules, trim if $stdin; if ($stdin) { my @from_stdin = ; for (@from_stdin) { s/\A\s*//; s/\s*\z//; } push @modules, @from_stdin; } pod2usage( -exitval => 1, -message => 'No modules selected') unless @modules; if ($namespace) { my @found; for my $ns (@modules) { push @found, $ns if find_installed($ns, @search); push @found, find_in_namespace($ns, @search); } @modules = @found; } # We can just print and exit if we're just interested in module names. # However, if we also want versions, we have to get the path(s) anyway. if ($name_only and not $version) { print map { "$_\n" } @modules; exit 0; } # Find the maximum length of module names my $width = max map { length } @modules; my $exit = 0; MODULE: for my $module (@modules) { unless (is_valid_module_name($module)) { # Maybe the module is actually a path: my $new = path_to_module($module) || fs_path_to_module($module); if ($new) { $module = $new; } else { $exit = 2; warn "'$module' is not a valid module name\n"; next MODULE; } } if ($paths) { print module_path $module, "\n"; next MODULE; } my @paths = $all ? all_installed($module, @search) : find_installed($module, @search) ; my $prefix = ''; unless ($quiet or @modules == 1 or $name_only) { # print the module name as well as the path $prefix = sprintf("%-${width}s - ", $module); } if (@paths) { for my $path (@paths) { if ($version) { my $version = eval { MM->parse_version($path) }; if ($@) { warn "$0: Error finding version for '$module': $@\n"; $exit = 2; } # We might not want to display the path $path = $module if $name_only; $path .= defined $version ? " [ $version ]" : ''; } print $prefix, $path, "\n"; } } else { $exit = 2; print $prefix, "not found\n" unless $quiet; } } exit $exit; sub version { my $path = module_is_loaded('Module::Util'); print "pm_which $VERSION\n", "Using Module::Util $Module::Util::VERSION at $path\n"; exit 0; } __END__ =head1 DESCRIPTION This tool reports the locations of installed perl modules. By default it lists the location of each specified module that would be loaded by require. =head1 OPTION DETAILS =head2 quiet Under quiet mode, module names are suppressed and missing modules are not reported. Normal output: $ pm_which Module::One Module::Two Missing::Module Module::One - /path/to/Module/One.pm Module::Two - /path/to/Module/Two.pm Missing::Module - not found Under --quiet: $ pm_which -q Module::One Module::Two Missing::Module /path/to/Module/One.pm /path/to/Module/Two.pm =head2 paths In "paths" mode, each module is simply converted into a relative file path. This is possible even when the module is not installed. $ pm_which -p Missing::Module Missing/Module.pm =head2 all When the "all" switch is specified, all installed modules will be reported, not just the first one. This is useful for determining when there is a module installed in multiple locations. $ pm_which -a MyModule /path/to/MyModule.pm /home/me/perl/MyModule.pm =head2 namespace Arguments are taken as namespaces to search under. $ pm_which -n MyModule MyModule - /path/to/MyModule.pm MyModule::Foo - /path/to/MyModule/Foo.pm MyModule::Foo::Bar - /path/to/MyModule/Foo/Bar.pm =head2 -m Disables printing of module paths. This is only really useful in conjunction with --namespace. $ pm_which -nm MyModule MyModule MyModule::Foo MyModule::Foo::Bar =head2 -V Prints the version of each module, according to L. $ pm_which -V MyModule MyModule - /path/to/MyModule.pm [ 1.00 ] $ pm_which -Vnm MyModule MyModule [ 1.00 ] MyModule::Foo [ 0.01 ] MyModule::Foo::Bar [ undef ] =head2 dump Dumps the paths that would be searched and exits. This is @INC modified by any -I switches. $ pm_which --dump /usr/lib/perl5/site_perl/5.8.6 /usr/lib/perl5/vendor_perl/5.8.6 ... $ pm_which -I lib --dump -I blib/lib lib blib/lib /usr/lib/perl5/site_perl/5.8.6 ... =head2 version Prints the version number of the script, plus the version and path of Module::Util that was loaded. =head1 EXIT CODES =over =item * 0 - Everything was OK =item * 1 - Initialisation failed (bad switches?) =item * 2 - Some modules were not installed =back =head1 SEE ALSO This utility comes with L. =head1 AUTHOR Matt Lawrence Emattlaw@cpan.orgE =cut vim: ts=8 sts=4 sw=4 sr et