|
Packit Service |
d63224 |
use strict;
|
|
Packit Service |
d63224 |
use warnings;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
package inc::latest;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# ABSTRACT: use modules bundled in inc/ if they are newer than installed ones
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
our $VERSION = '0.500';
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
package inc::latest;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
use Carp;
|
|
Packit Service |
d63224 |
use File::Basename ();
|
|
Packit Service |
d63224 |
use File::Spec ();
|
|
Packit Service |
d63224 |
use File::Path ();
|
|
Packit Service |
d63224 |
use IO::File ();
|
|
Packit Service |
d63224 |
use File::Copy ();
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# track and return modules loaded by inc::latest
|
|
Packit Service |
d63224 |
my @loaded_modules;
|
|
Packit Service |
d63224 |
sub loaded_modules { @loaded_modules }
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# must ultimately "goto" the import routine of the module to be loaded
|
|
Packit Service |
d63224 |
# so that the calling package is correct when $mod->import() runs.
|
|
Packit Service |
d63224 |
sub import {
|
|
Packit Service |
d63224 |
my ( $package, $mod, @args ) = @_;
|
|
Packit Service |
d63224 |
return unless ( defined $mod );
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
my $private_path = 'inc/latest/private.pm';
|
|
Packit Service |
d63224 |
if ( -e $private_path ) {
|
|
Packit Service |
d63224 |
# user mode - delegate work to bundled private module
|
|
Packit Service |
d63224 |
require $private_path;
|
|
Packit Service |
d63224 |
splice( @_, 0, 1, 'inc::latest::private' );
|
|
Packit Service |
d63224 |
goto \&inc::latest::private::import;
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# author mode - just record and load the modules
|
|
Packit Service |
d63224 |
push( @loaded_modules, $mod );
|
|
Packit Service |
d63224 |
require inc::latest::private;
|
|
Packit Service |
d63224 |
goto \&inc::latest::private::_load_module;
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
sub write {
|
|
Packit Service |
d63224 |
my $package = shift;
|
|
Packit Service |
d63224 |
my ( $where, @preload ) = @_;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
warn "should really be writing in inc/" unless $where =~ /inc$/;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# write inc/latest.pm
|
|
Packit Service |
d63224 |
File::Path::mkpath($where);
|
|
Packit Service |
d63224 |
my $fh = IO::File->new( File::Spec->catfile( $where, 'latest.pm' ), "w" );
|
|
Packit Service |
d63224 |
print {$fh} "# This stub created by inc::latest $VERSION\n";
|
|
Packit Service |
d63224 |
print {$fh} <<'HERE';
|
|
Packit Service |
d63224 |
package inc::latest;
|
|
Packit Service |
d63224 |
use strict;
|
|
Packit Service |
d63224 |
use vars '@ISA';
|
|
Packit Service |
d63224 |
require inc::latest::private;
|
|
Packit Service |
d63224 |
@ISA = qw/inc::latest::private/;
|
|
Packit Service |
d63224 |
HERE
|
|
Packit Service |
d63224 |
if (@preload) {
|
|
Packit Service |
d63224 |
print {$fh} "\npackage inc::latest::preload;\n";
|
|
Packit Service |
d63224 |
for my $mod (@preload) {
|
|
Packit Service |
d63224 |
print {$fh} "inc::latest->import('$mod');\n";
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
print {$fh} "\n1;\n";
|
|
Packit Service |
d63224 |
close $fh;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# write inc/latest/private;
|
|
Packit Service |
d63224 |
require inc::latest::private;
|
|
Packit Service |
d63224 |
File::Path::mkpath( File::Spec->catdir( $where, 'latest' ) );
|
|
Packit Service |
d63224 |
my $from = $INC{'inc/latest/private.pm'};
|
|
Packit Service |
d63224 |
my $to = File::Spec->catfile( $where, 'latest', 'private.pm' );
|
|
Packit Service |
d63224 |
File::Copy::copy( $from, $to ) or die "Couldn't copy '$from' to '$to': $!";
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
return 1;
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
sub bundle_module {
|
|
Packit Service |
d63224 |
my ( $package, $module, $where ) = @_;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# create inc/inc_$foo
|
|
Packit Service |
d63224 |
( my $dist = $module ) =~ s{::}{-}g;
|
|
Packit Service |
d63224 |
my $inc_lib = File::Spec->catdir( $where, "inc_$dist" );
|
|
Packit Service |
d63224 |
File::Path::mkpath $inc_lib;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# get list of files to copy
|
|
Packit Service |
d63224 |
require ExtUtils::Installed;
|
|
Packit Service |
d63224 |
# workaround buggy EU::Installed check of @INC
|
|
Packit Service |
d63224 |
my $inst = ExtUtils::Installed->new( extra_libs => [@INC] );
|
|
Packit Service |
d63224 |
my $packlist = $inst->packlist($module) or die "Couldn't find packlist";
|
|
Packit Service |
d63224 |
my @files = grep { /\.pm$/ } keys %$packlist;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# figure out prefix
|
|
Packit Service |
d63224 |
my $mod_path = quotemeta $package->_mod2path($module);
|
|
Packit Service |
d63224 |
my ($prefix) = grep { /$mod_path$/ } @files;
|
|
Packit Service |
d63224 |
$prefix =~ s{$mod_path$}{};
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# copy files
|
|
Packit Service |
d63224 |
for my $from (@files) {
|
|
Packit Service |
d63224 |
next unless $from =~ /\.pm$/;
|
|
Packit Service |
d63224 |
( my $mod_path = $from ) =~ s{^\Q$prefix\E}{};
|
|
Packit Service |
d63224 |
my $to = File::Spec->catfile( $inc_lib, $mod_path );
|
|
Packit Service |
d63224 |
File::Path::mkpath( File::Basename::dirname($to) );
|
|
Packit Service |
d63224 |
File::Copy::copy( $from, $to ) or die "Couldn't copy '$from' to '$to': $!";
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
return 1;
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# Translate a module name into a directory/file.pm to search for in @INC
|
|
Packit Service |
d63224 |
sub _mod2path {
|
|
Packit Service |
d63224 |
my ( $self, $mod ) = @_;
|
|
Packit Service |
d63224 |
my @parts = split /::/, $mod;
|
|
Packit Service |
d63224 |
$parts[-1] .= '.pm';
|
|
Packit Service |
d63224 |
return $parts[0] if @parts == 1;
|
|
Packit Service |
d63224 |
return File::Spec->catfile(@parts);
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
1;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# vim: ts=4 sts=4 sw=4 tw=75 et:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
__END__
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=pod
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=encoding UTF-8
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 NAME
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
inc::latest - use modules bundled in inc/ if they are newer than installed ones
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 VERSION
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
version 0.500
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 SYNOPSIS
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
# in Makefile.PL or Build.PL
|
|
Packit Service |
d63224 |
use inc::latest 'Some::Configure::Prereq';
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 DESCRIPTION
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
B<WARNING -- THIS IS AN EXPERIMENTAL MODULE>. It was originally bundled
|
|
Packit Service |
d63224 |
(as an experiment) with L<Module::Build> and has been split out for more
|
|
Packit Service |
d63224 |
general use.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
The C<inc::latest> module helps bootstrap configure-time dependencies for
|
|
Packit Service |
d63224 |
CPAN distributions. These dependencies get bundled into the C<inc>
|
|
Packit Service |
d63224 |
directory within a distribution and are used by F<Makefile.PL> or F<Build.PL>.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Arguments to C<inc::latest> are module names that are checked against both
|
|
Packit Service |
d63224 |
the current C<@INC> array and against specially-named directories in
|
|
Packit Service |
d63224 |
C<inc>. If the bundled version is newer than the installed one (or the
|
|
Packit Service |
d63224 |
module isn't installed, then, the bundled directory is added to the start
|
|
Packit Service |
d63224 |
of C<@INC> and the module is loaded from there.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
There are actually two variations of C<inc::latest> -- one for authors and
|
|
Packit Service |
d63224 |
one for the C<inc> directory. For distribution authors, the C<inc::latest>
|
|
Packit Service |
d63224 |
installed in the system will record modules loaded via C<inc::latest> and
|
|
Packit Service |
d63224 |
can be used to create the bundled files in C<inc>, including writing the
|
|
Packit Service |
d63224 |
second variation as C<inc/latest.pm>.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This second C<inc::latest> is the one that is loaded in a distribution
|
|
Packit Service |
d63224 |
being installed (e.g. from F<Makefile.PL> or F<Build.PL>). This bundled
|
|
Packit Service |
d63224 |
C<inc::latest> is the one that determines which module to load.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 Special notes on bundling
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
The C<inc::latest> module creates bundled directories based on the packlist
|
|
Packit Service |
d63224 |
file of an installed distribution. Even though C<inc::latest> takes module
|
|
Packit Service |
d63224 |
name arguments, it is better to think of it as bundling and making
|
|
Packit Service |
d63224 |
available entire I<distributions>. When a module is loaded through
|
|
Packit Service |
d63224 |
C<inc::latest>, it looks in all bundled distributions in C<inc/> for a
|
|
Packit Service |
d63224 |
newer module than can be found in the existing C<@INC> array.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Thus, the module-name provided should usually be the "top-level" module
|
|
Packit Service |
d63224 |
name of a distribution, though this is not strictly required.
|
|
Packit Service |
d63224 |
C<inc::latest> has a number of heuristics to discover module names,
|
|
Packit Service |
d63224 |
allowing users to do things like this:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
use inc::latest 'Devel::AssertOS::Unix';
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
even though Devel::AssertOS::Unix is contained within the Devel-CheckOS
|
|
Packit Service |
d63224 |
distribution.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
At the current time, packlists are required. Thus, bundling dual-core
|
|
Packit Service |
d63224 |
modules may require a 'forced install' over versions in the latest version
|
|
Packit Service |
d63224 |
of perl in order to create the necessary packlist for bundling.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 Managing dependency chains
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Before bundling a distribution you must ensure that all prerequisites are
|
|
Packit Service |
d63224 |
also bundled and load in the correct order.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
For example, if you need C<Wibble>, but C<Wibble> depends on C<Wobble>,
|
|
Packit Service |
d63224 |
and you have bundled C<Module::Build>, your F<Build.PL> might look like this:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
use inc::latest 'Wobble';
|
|
Packit Service |
d63224 |
use inc::latest 'Wibble';
|
|
Packit Service |
d63224 |
use inc::latest 'Module::Build';
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Module::Build->new(
|
|
Packit Service |
d63224 |
module_name => 'Foo::Bar',
|
|
Packit Service |
d63224 |
license => 'perl',
|
|
Packit Service |
d63224 |
)->create_build_script;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Authors are strongly suggested to limit the bundling of additional
|
|
Packit Service |
d63224 |
dependencies if at all possible and to carefully test their distribution
|
|
Packit Service |
d63224 |
tarballs before uploading to CPAN.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 USAGE
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 As bundled in inc/
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Using L</Author-mode>, a special stub module will be created in your
|
|
Packit Service |
d63224 |
distribute directory as F<inc/latest.pm>. In your F<Makefile.PL> or
|
|
Packit Service |
d63224 |
F<Build.PL>, you can then load C<inc::latest> to load bundled modules.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
When calling C<use>, the bundled C<inc::latest> takes a single module name
|
|
Packit Service |
d63224 |
and optional arguments to pass to that module's own import method.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
use inc::latest 'Foo::Bar' qw/foo bar baz/;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
The implementation is private. Only the C<import> method is public.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 Author-mode
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
When you have L<inc::latest> installed from CPAN, then you are in author-mode
|
|
Packit Service |
d63224 |
if any of the Author-mode methods are available. For example:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
if ( inc::latest->can('write') ) {
|
|
Packit Service |
d63224 |
inc::latest->write('inc');
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Using author-mode, you can create the stub F<inc/latest.pm> and bundle
|
|
Packit Service |
d63224 |
modules into F<inc>.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=over 4
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=item loaded_modules()
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
my @list = inc::latest->loaded_modules;
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This takes no arguments and always returns a list of module names requested
|
|
Packit Service |
d63224 |
for loading via "use inc::latest 'MODULE'", regardless of whether the load
|
|
Packit Service |
d63224 |
was successful or not.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=item write()
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
inc::latest->write( 'inc' );
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This writes the bundled version of inc::latest to the directory name given
|
|
Packit Service |
d63224 |
as an argument. It almost all cases, it should be 'C<inc>'.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=item bundle_module()
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
for my $mod ( inc::latest->loaded_modules ) {
|
|
Packit Service |
d63224 |
inc::latest->bundle_module($mod, $dir);
|
|
Packit Service |
d63224 |
}
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
If $mod corresponds to a packlist, then this function creates a
|
|
Packit Service |
d63224 |
specially-named directory in $dir and copies all .pm files from the modlist
|
|
Packit Service |
d63224 |
to the new directory (which almost always should just be 'inc'). For
|
|
Packit Service |
d63224 |
example, if Foo::Bar is the name of the module, and $dir is 'inc', then the
|
|
Packit Service |
d63224 |
directory would be 'inc/inc_Foo-Bar' and contain files like this:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
inc/inc_Foo-Bar/Foo/Bar.pm
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Currently, $mod B<must> have a packlist. If this is not the case (e.g. for
|
|
Packit Service |
d63224 |
a dual-core module), then the bundling will fail. You may be able to
|
|
Packit Service |
d63224 |
create a packlist by forced installing the module on top of the version
|
|
Packit Service |
d63224 |
that came with core Perl.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=back
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 SUPPORT
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 Bugs / Feature Requests
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Please report any bugs or feature requests through the issue tracker
|
|
Packit Service |
d63224 |
at L<https://github.com/dagolden/inc-latest/issues>.
|
|
Packit Service |
d63224 |
You will be notified automatically of any progress on your issue.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head2 Source Code
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This is open source software. The code repository is available for
|
|
Packit Service |
d63224 |
public review and contribution under the terms of the license.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
L<https://github.com/dagolden/inc-latest>
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
git clone https://github.com/dagolden/inc-latest.git
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 AUTHORS
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=over 4
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=item *
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
David Golden <dagolden@cpan.org>
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=item *
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
Eric Wilhelm <ewilhelm@cpan.org>
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=back
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=head1 COPYRIGHT AND LICENSE
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This software is Copyright (c) 2009 by David Golden.
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
This is free software, licensed under:
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
The Apache License, Version 2.0, January 2004
|
|
Packit Service |
d63224 |
|
|
Packit Service |
d63224 |
=cut
|