Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

announce missing modules

by Anonymous Monk
on Feb 22, 2008 at 16:53 UTC ( #669603=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Often I use obscure modules on a number of machines. The usual perl response to missing modules is to say that the module wasn't found and list the @INC path. Once one module is installed the same error is repeated for the next missing module. I find it much more helpful if the script spits out a list of missing modules so I can install them all at once. I use:
our @missing = grep( !eval "use $_; 1", qw ( Filesys::Df Text::Table )) and die "Please install CPAN modules: cpan -i @missing\n";
Any suggestion for alternatives?

Replies are listed 'Best First'.
Re: announce missing modules
by marto (Cardinal) on Feb 22, 2008 at 17:00 UTC
    You could create an AutoBundle (perl -MCPAN -e autobundle) and roll that out to each machine and install all of the modules you require that way, rather than report was is missing.

    Update: For further information about this see responses to perl modules replication and Mirror CPAN installed modules

    Hope this helps

      Thanks for the suggestion.

      There are lots of scripts; some run on these machines and some run on those machines. The scripts also morph over time and the list of modules changes. So the set of required modules depends on the machine and increases over time as the script changes.

      I could use autobundle but this is means I have to do the autobundle regularly from a configured machine. I'd rather just have the script tell me what I need to install.

Re: announce missing modules
by grinder (Bishop) on Feb 22, 2008 at 22:19 UTC

    You know, there's a module around that does this (naturally :).

    It works by overloading use, and intercepts attempts to load modules that don't exists. It then intervenes and downloads, compiles, and installs the module, and then the program picks up where it left off. So it's a bit slow the first time around, but much faster afterwards.

    All you have to do is add the use of this module to your program and set things up so that it goes to a trusted machine from which to download the file.

    The only trouble is I can't remember for the life of me what it's called...

    • another intruder with the mooring in the heart of the Perl

Re: announce missing modules
by jasonk (Parson) on Feb 23, 2008 at 17:29 UTC

    You can put code refs in @INC, which means you could do this automatically, rather than having to wrap your list of modules...

    package MissingModules; my %missing = (); BEGIN { push( @INC, sub { my ( $code, $mod ) = @_; $mod =~ s#/#::#g; $mod =~ s/\.pm$//; $missing{ $mod }++; open( my $fh, '+>', undef ); print {$fh} "package $mod;\n1;\n"; seek( $fh, 0, 0 ); return $fh; } ); } INIT { if ( my @list = keys %missing ) { warn "Please install CPAN modules: cpan -i @list\n"; exit; } } 1;

    Then in your other code:

    #!/usr/bin/perl use MissingModules; use CGI; use Foo; use Bar; use Baz; 1;

    When you run it, you will get...

    % perl Please install CPAN modules: cpan -i Bar Baz Foo

    We're not surrounded, we're in a target-rich environment!
      That's a great idea. I started to play with something similar and got the following for the anon function on the @INC array.
      BEGIN { use 5.8.0; use vars qw(@missing); push @INC, sub { my ($coderef, $filename) = @_; # Ignore non-modules. return undef unless ($filename =~ s/.pm$//); # Remember the module. $filename =~ s/\//::/g; push @missing, $filename; # Return a dummy file handle. open my $FH, '<', \'1;'; $FH; }; }
      The INIT block is a great idea.
      INIT { # Check and clean up. die "Missing modules.\n\tcpan -i ", join(' ',' @missing), "\n\ +n" if (@missing); pop @INC; }
      The open my $FH, '<', \'1;'; is available in perl 5.8.8.

      Is there a better way to deduce the module name than removing the .pm extension and replacing /s with ::? Will it work on non-UNIX platforms?

      Popping the function off again seems like a good idea.

        Just for the record, I found the flaw in this scheme. One of my included modules includes 'Storable', which tries to include 'Log::Agent'. If it fails then the 'Storable' module does something else. The above @INC scheme forces the user to install the conditional module. This shouldn't happen.

        So back to the old method (slightly refined to handle module versions and import lists)

        { our @missing = map +(m/^(\S+)/), grep !eval "use $_; 1", grep $_, split /\s*\n\s*/, " Storable File::Basename A::B wq(a b c) Foo::Bar CGI qw/:standard/ " and die "Please install CPAN modules: cpan -i @missing\n"; }

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://669603]
Approved by kyle
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2021-10-26 02:43 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (90 votes). Check out past polls.