[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 package CPANPLUS::inc; 2 3 =head1 NAME 4 5 CPANPLUS::inc 6 7 =head1 DESCRIPTION 8 9 OBSOLETE 10 11 =cut 12 13 sub original_perl5opt { $ENV{PERL5OPT} }; 14 sub original_perl5lib { $ENV{PERL5LIB} }; 15 sub original_inc { @INC }; 16 17 1; 18 19 __END__ 20 21 use strict; 22 use vars qw[$DEBUG $VERSION $ENABLE_INC_HOOK %LIMIT $QUIET]; 23 use File::Spec (); 24 use Config (); 25 26 ### 5.6.1. nags about require + bareword otherwise ### 27 use lib (); 28 29 $QUIET = 0; 30 $DEBUG = 0; 31 %LIMIT = (); 32 33 =pod 34 35 =head1 NAME 36 37 CPANPLUS::inc - runtime inclusion of privately bundled modules 38 39 =head1 SYNOPSIS 40 41 ### set up CPANPLUS::inc to do it's thing ### 42 BEGIN { use CPANPLUS::inc }; 43 44 ### enable debugging ### 45 use CPANPLUS::inc qw[DEBUG]; 46 47 =head1 DESCRIPTION 48 49 This module enables the use of the bundled modules in the 50 C<CPANPLUS/inc> directory of this package. These modules are bundled 51 to make sure C<CPANPLUS> is able to bootstrap itself. It will do the 52 following things: 53 54 =over 4 55 56 =item Put a coderef at the beginning of C<@INC> 57 58 This allows us to decide which module to load, and where to find it. 59 For details on what we do, see the C<INTERESTING MODULES> section below. 60 Also see the C<CAVEATS> section. 61 62 =item Add the full path to the C<CPANPLUS/inc> directory to C<$ENV{PERL5LIB>. 63 64 This allows us to find our bundled modules even if we spawn off a new 65 process. Although it's not able to do the selective loading as the 66 coderef in C<@INC> could, it's a good fallback. 67 68 =back 69 70 =head1 METHODS 71 72 =head2 CPANPLUS::inc->inc_path() 73 74 Returns the full path to the C<CPANPLUS/inc> directory. 75 76 =head2 CPANPLUS::inc->my_path() 77 78 Returns the full path to be added to C<@INC> to load 79 C<CPANPLUS::inc> from. 80 81 =head2 CPANPLUS::inc->installer_path() 82 83 Returns the full path to the C<CPANPLUS/inc/installers> directory. 84 85 =cut 86 87 { my $ext = '.pm'; 88 my $file = (join '/', split '::', __PACKAGE__) . $ext; 89 90 ### os specific file path, if you're not on unix 91 my $osfile = File::Spec->catfile( split('::', __PACKAGE__) ) . $ext; 92 93 ### this returns a unixy path, compensate if you're on non-unix 94 my $path = File::Spec->rel2abs( 95 File::Spec->catfile( split '/', $INC{$file} ) 96 ); 97 98 ### don't forget to quotemeta; win32 paths are special 99 my $qm_osfile = quotemeta $osfile; 100 my $path_to_me = $path; $path_to_me =~ s/$qm_osfile$//i; 101 my $path_to_inc = $path; $path_to_inc =~ s/$ext$//i; 102 my $path_to_installers = File::Spec->catdir( $path_to_inc, 'installers' ); 103 104 sub inc_path { return $path_to_inc } 105 sub my_path { return $path_to_me } 106 sub installer_path { return $path_to_installers } 107 } 108 109 =head2 CPANPLUS::inc->original_perl5lib 110 111 Returns the value of $ENV{PERL5LIB} the way it was when C<CPANPLUS::inc> 112 got loaded. 113 114 =head2 CPANPLUS::inc->original_perl5opt 115 116 Returns the value of $ENV{PERL5OPT} the way it was when C<CPANPLUS::inc> 117 got loaded. 118 119 =head2 CPANPLUS::inc->original_inc 120 121 Returns the value of @INC the way it was when C<CPANPLUS::inc> got 122 loaded. 123 124 =head2 CPANPLUS::inc->limited_perl5opt(@modules); 125 126 Returns a string you can assign to C<$ENV{PERL5OPT}> to have a limited 127 include facility from C<CPANPLUS::inc>. It will roughly look like: 128 129 -I/path/to/cpanplus/inc -MCPANPLUS::inc=module1,module2 130 131 =cut 132 133 { my $org_opt = $ENV{PERL5OPT}; 134 my $org_lib = $ENV{PERL5LIB}; 135 my @org_inc = @INC; 136 137 sub original_perl5opt { $org_opt || ''}; 138 sub original_perl5lib { $org_lib || ''}; 139 sub original_inc { @org_inc, __PACKAGE__->my_path }; 140 141 sub limited_perl5opt { 142 my $pkg = shift; 143 my $lim = join ',', @_ or return; 144 145 ### -Icp::inc -Mcp::inc=mod1,mod2,mod3 146 my $opt = '-I' . __PACKAGE__->my_path . ' ' . 147 '-M' . __PACKAGE__ . "=$lim"; 148 149 $opt .= $Config::Config{'path_sep'} . 150 CPANPLUS::inc->original_perl5opt 151 if CPANPLUS::inc->original_perl5opt; 152 153 return $opt; 154 } 155 } 156 157 =head2 CPANPLUS::inc->interesting_modules() 158 159 Returns a hashref with modules we're interested in, and the minimum 160 version we need to find. 161 162 It would looks something like this: 163 164 { File::Fetch => 0.06, 165 IPC::Cmd => 0.22, 166 .... 167 } 168 169 =cut 170 171 { 172 my $map = { 173 ### used to have 0.80, but not it was never released by coral 174 ### 0.79 *should* be good enough for now... asked coral to 175 ### release 0.80 on 10/3/2006 176 'IPC::Run' => '0.79', 177 'File::Fetch' => '0.07', 178 #'File::Spec' => '0.82', # can't, need it ourselves... 179 'IPC::Cmd' => '0.24', 180 'Locale::Maketext::Simple' => 0, 181 'Log::Message' => 0, 182 'Module::Load' => '0.10', 183 'Module::Load::Conditional' => '0.07', 184 'Params::Check' => '0.22', 185 'Term::UI' => '0.05', 186 'Archive::Extract' => '0.07', 187 'Archive::Tar' => '1.23', 188 'IO::Zlib' => '1.04', 189 'Object::Accessor' => '0.03', 190 'Module::CoreList' => '1.97', 191 'Module::Pluggable' => '2.4', 192 'Module::Loaded' => 0, 193 #'Config::Auto' => 0, # not yet, not using it yet 194 }; 195 196 sub interesting_modules { return $map; } 197 } 198 199 200 =head1 INTERESTING MODULES 201 202 C<CPANPLUS::inc> doesn't even bother to try find and find a module 203 it's not interested in. A list of I<interesting modules> can be 204 obtained using the C<interesting_modules> method described above. 205 206 Note that all subclassed modules of an C<interesting module> will 207 also be attempted to be loaded, but a version will not be checked. 208 209 When it however does encounter a module it is interested in, it will 210 do the following things: 211 212 =over 4 213 214 =item Loop over your @INC 215 216 And for every directory it finds there (skipping all non directories 217 -- see the C<CAVEATS> section), see if the module requested can be 218 found there. 219 220 =item Check the version on every suitable module found in @INC 221 222 After a list of modules has been gathered, the version of each of them 223 is checked to find the one with the highest version, and return that as 224 the module to C<use>. 225 226 This enables us to use a recent enough version from our own bundled 227 modules, but also to use a I<newer> module found in your path instead, 228 if it is present. Thus having access to bugfixed versions as they are 229 released. 230 231 If for some reason no satisfactory version could be found, a warning 232 will be emitted. See the C<DEBUG> section for more details on how to 233 find out exactly what C<CPANPLUS::inc> is doing. 234 235 =back 236 237 =cut 238 239 { my $Loaded; 240 my %Cache; 241 242 243 ### returns the path to a certain module we found 244 sub path_to { 245 my $self = shift; 246 my $mod = shift or return; 247 248 ### find the directory 249 my $path = $Cache{$mod}->[0][2] or return; 250 251 ### probe them explicitly for a special file, because the 252 ### dir we found the file in vs our own paths may point to the 253 ### same location, but might not pass an 'eq' test. 254 255 ### it's our inc-path 256 return __PACKAGE__->inc_path 257 if -e File::Spec->catfile( $path, '.inc' ); 258 259 ### it's our installer path 260 return __PACKAGE__->installer_path 261 if -e File::Spec->catfile( $path, '.installers' ); 262 263 ### it's just some dir... 264 return $path; 265 } 266 267 ### just a debug method 268 sub _show_cache { return \%Cache }; 269 270 sub import { 271 my $pkg = shift; 272 273 ### filter DEBUG, and toggle the global 274 map { $LIMIT{$_} = 1 } 275 grep { /DEBUG/ ? ++$DEBUG && 0 : 276 /QUIET/ ? ++$QUIET && 0 : 277 1 278 } @_; 279 280 ### only load once ### 281 return 1 if $Loaded++; 282 283 ### first, add our own private dir to the end of @INC: 284 { 285 push @INC, __PACKAGE__->my_path, __PACKAGE__->inc_path, 286 __PACKAGE__->installer_path; 287 288 ### XXX stop doing this, there's no need for it anymore; 289 ### none of the shell outs need to have this set anymore 290 # ### add the path to this module to PERL5OPT in case 291 # ### we spawn off some programs... 292 # ### then add this module to be loaded in PERL5OPT... 293 # { local $^W; 294 # $ENV{'PERL5LIB'} .= $Config::Config{'path_sep'} 295 # . __PACKAGE__->my_path 296 # . $Config::Config{'path_sep'} 297 # . __PACKAGE__->inc_path; 298 # 299 # $ENV{'PERL5OPT'} = '-M'. __PACKAGE__ . ' ' 300 # . ($ENV{'PERL5OPT'} || ''); 301 # } 302 } 303 304 ### next, find the highest version of a module that 305 ### we care about. very basic check, but will 306 ### have to do for now. 307 lib->import( sub { 308 my $path = pop(); # path to the pm 309 my $module = $path or return; # copy of the path, to munge 310 my @parts = split qr!\\|/!, $path; # dirs + file name; could be 311 # win32 paths =/ 312 my $file = pop @parts; # just the file name 313 my $map = __PACKAGE__->interesting_modules; 314 315 ### translate file name to module name 316 ### could contain win32 paths delimiters 317 $module =~ s!/|\\!::!g; $module =~ s/\.pm//i; 318 319 my $check_version; my $try; 320 ### does it look like a module we care about? 321 my ($interesting) = grep { $module =~ /^$_/ } keys %$map; 322 ++$try if $interesting; 323 324 ### do we need to check the version too? 325 ++$check_version if exists $map->{$module}; 326 327 ### we don't care ### 328 unless( $try ) { 329 warn __PACKAGE__ .": Not interested in '$module'\n" if $DEBUG; 330 return; 331 332 ### we're not allowed 333 } elsif ( $try and keys %LIMIT ) { 334 unless( grep { $module =~ /^$_/ } keys %LIMIT ) { 335 warn __PACKAGE__ .": Limits active, '$module' not allowed ". 336 "to be loaded" if $DEBUG; 337 return; 338 } 339 } 340 341 ### found filehandles + versions ### 342 my @found; 343 DIR: for my $dir (@INC) { 344 next DIR unless -d $dir; 345 346 ### get the full path to the module ### 347 my $pm = File::Spec->catfile( $dir, @parts, $file ); 348 349 ### open the file if it exists ### 350 if( -e $pm ) { 351 my $fh; 352 unless( open $fh, "$pm" ) { 353 warn __PACKAGE__ .": Could not open '$pm': $!\n" 354 if $DEBUG; 355 next DIR; 356 } 357 358 my $found; 359 ### XXX stolen from module::load::conditional ### 360 while (local $_ = <$fh> ) { 361 362 ### the following regexp comes from the 363 ### ExtUtils::MakeMaker documentation. 364 if ( /([\$*])(([\w\:\']*)\bVERSION)\b.*\=/ ) { 365 366 ### this will eval the version in to $VERSION if it 367 ### was declared as $VERSION in the module. 368 ### else the result will be in $res. 369 ### this is a fix on skud's Module::InstalledVersion 370 371 local $VERSION; 372 my $res = eval $_; 373 374 ### default to '0.0' if there REALLY is no version 375 ### all to satisfy warnings 376 $found = $VERSION || $res || '0.0'; 377 378 ### found what we came for 379 last if $found; 380 } 381 } 382 383 ### no version defined at all? ### 384 $found ||= '0.0'; 385 386 warn __PACKAGE__ .": Found match for '$module' in '$dir' " 387 ."with version '$found'\n" if $DEBUG; 388 389 ### reset the position of the filehandle ### 390 seek $fh, 0, 0; 391 392 ### store the found version + filehandle it came from ### 393 push @found, [ $found, $fh, $dir, $pm ]; 394 } 395 396 } # done looping over all the dirs 397 398 ### nothing found? ### 399 unless (@found) { 400 warn __PACKAGE__ .": Unable to find any module named " 401 . "'$module'\n" if $DEBUG; 402 return; 403 } 404 405 ### find highest version 406 ### or the one in the same dir as a base module already loaded 407 ### or otherwise, the one not bundled 408 ### or otherwise the newest 409 my @sorted = sort { 410 _vcmp($b->[0], $a->[0]) || 411 ($Cache{$interesting} 412 ?($b->[2] eq $Cache{$interesting}->[0][2]) <=> 413 ($a->[2] eq $Cache{$interesting}->[0][2]) 414 : 0 ) || 415 (($a->[2] eq __PACKAGE__->inc_path) <=> 416 ($b->[2] eq __PACKAGE__->inc_path)) || 417 (-M $a->[3] <=> -M $b->[3]) 418 } @found; 419 420 warn __PACKAGE__ .": Best match for '$module' is found in " 421 ."'$sorted[0][2]' with version '$sorted[0][0]'\n" 422 if $DEBUG; 423 424 if( $check_version and 425 not (_vcmp($sorted[0][0], $map->{$module}) >= 0) 426 ) { 427 warn __PACKAGE__ .": Cannot find high enough version for " 428 ."'$module' -- need '$map->{$module}' but " 429 ."only found '$sorted[0][0]'. Returning " 430 ."highest found version but this may cause " 431 ."problems\n" unless $QUIET; 432 }; 433 434 ### right, so that damn )#$(*@#)(*@#@ Module::Build makes 435 ### assumptions about the environment (especially its own tests) 436 ### and blows up badly if it's loaded via CP::inc :( 437 ### so, if we find a newer version on disk (which would happen when 438 ### upgrading or having upgraded, just pretend we didn't find it, 439 ### let it be loaded via the 'normal' way. 440 ### can't even load the *proper* one via our CP::inc, as it will 441 ### get upset just over the fact it's loaded via a non-standard way 442 if( $module =~ /^Module::Build/ and 443 $sorted[0][2] ne __PACKAGE__->inc_path and 444 $sorted[0][2] ne __PACKAGE__->installer_path 445 ) { 446 warn __PACKAGE__ .": Found newer version of 'Module::Build::*' " 447 ."elsewhere in your path. Pretending to not " 448 ."have found it\n" if $DEBUG; 449 return; 450 } 451 452 ### store what we found for this module 453 $Cache{$module} = \@sorted; 454 455 ### best matching filehandle ### 456 return $sorted[0][1]; 457 } ); 458 } 459 } 460 461 ### XXX copied from C::I::Utils, so there's no circular require here! 462 sub _vcmp { 463 my ($x, $y) = @_; 464 s/_//g foreach $x, $y; 465 return $x <=> $y; 466 } 467 468 =pod 469 470 =head1 DEBUG 471 472 Since this module does C<Clever Things> to your search path, it might 473 be nice sometimes to figure out what it's doing, if things don't work 474 as expected. You can enable a debug trace by calling the module like 475 this: 476 477 use CPANPLUS::inc 'DEBUG'; 478 479 This will show you what C<CPANPLUS::inc> is doing, which might look 480 something like this: 481 482 CPANPLUS::inc: Found match for 'Params::Check' in 483 '/opt/lib/perl5/site_perl/5.8.3' with version '0.07' 484 CPANPLUS::inc: Found match for 'Params::Check' in 485 '/my/private/lib/CPANPLUS/inc' with version '0.21' 486 CPANPLUS::inc: Best match for 'Params::Check' is found in 487 '/my/private/lib/CPANPLUS/inc' with version '0.21' 488 489 =head1 CAVEATS 490 491 This module has 2 major caveats, that could lead to unexpected 492 behaviour. But currently I don't know how to fix them, Suggestions 493 are much welcomed. 494 495 =over 4 496 497 =item On multiple C<use lib> calls, our coderef may not be the first in @INC 498 499 If this happens, although unlikely in most situations and not happening 500 when calling the shell directly, this could mean that a lower (too low) 501 versioned module is loaded, which might cause failures in the 502 application. 503 504 =item Non-directories in @INC 505 506 Non-directories are right now skipped by CPANPLUS::inc. They could of 507 course lead us to newer versions of a module, but it's too tricky to 508 verify if they would. Therefor they are skipped. In the worst case 509 scenario we'll find the sufficing version bundled with CPANPLUS. 510 511 512 =cut 513 514 1; 515 516 # Local variables: 517 # c-indentation-style: bsd 518 # c-basic-offset: 4 519 # indent-tabs-mode: nil 520 # End: 521 # vim: expandtab shiftwidth=4: 522
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |