| 1 | package Module::Install; |
|---|
| 2 | $VERSION = '0.36'; |
|---|
| 3 | use FindBin; |
|---|
| 4 | |
|---|
| 5 | die << "." unless $INC{join('/', inc => split(/::/, __PACKAGE__)).'.pm'}; |
|---|
| 6 | Please invoke ${\__PACKAGE__} with: |
|---|
| 7 | |
|---|
| 8 | use inc::${\__PACKAGE__}; |
|---|
| 9 | |
|---|
| 10 | not: |
|---|
| 11 | |
|---|
| 12 | use ${\__PACKAGE__}; |
|---|
| 13 | |
|---|
| 14 | . |
|---|
| 15 | |
|---|
| 16 | use strict 'vars'; |
|---|
| 17 | use Cwd (); |
|---|
| 18 | use File::Find (); |
|---|
| 19 | use File::Path (); |
|---|
| 20 | |
|---|
| 21 | @inc::Module::Install::ISA = 'Module::Install'; |
|---|
| 22 | *inc::Module::Install::VERSION = *VERSION; |
|---|
| 23 | |
|---|
| 24 | sub import { |
|---|
| 25 | my $class = shift; |
|---|
| 26 | my $self = $class->new(@_); |
|---|
| 27 | |
|---|
| 28 | if (not -f $self->{file}) { |
|---|
| 29 | require Cwd; |
|---|
| 30 | die << "."; |
|---|
| 31 | *** Error: $self->{file} does not exist! |
|---|
| 32 | Current directory is @{[Cwd::abs_path(Cwd::cwd())]} |
|---|
| 33 | Program path is @{[Cwd::abs_path($FindBin::Bin)]} |
|---|
| 34 | *** Please report this issue to <perl6-compiler\@perl.org>. |
|---|
| 35 | . |
|---|
| 36 | require "$self->{path}/$self->{dispatch}.pm"; |
|---|
| 37 | File::Path::mkpath("$self->{prefix}/$self->{author}"); |
|---|
| 38 | $self->{admin} = |
|---|
| 39 | "$self->{name}::$self->{dispatch}"->new(_top => $self); |
|---|
| 40 | $self->{admin}->init; |
|---|
| 41 | @_ = ($class, _self => $self); |
|---|
| 42 | goto &{"$self->{name}::import"}; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | *{caller(0) . "::AUTOLOAD"} = $self->autoload; |
|---|
| 46 | |
|---|
| 47 | # Unregister loader and worker packages so subdirs can use them again |
|---|
| 48 | delete $INC{"$self->{file}"}; |
|---|
| 49 | delete $INC{"$self->{path}.pm"}; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | sub autoload { |
|---|
| 53 | my $self = shift; |
|---|
| 54 | my $caller = caller; |
|---|
| 55 | |
|---|
| 56 | my $cwd = Cwd::cwd(); |
|---|
| 57 | my $sym = "$caller\::AUTOLOAD"; |
|---|
| 58 | |
|---|
| 59 | $sym->{$cwd} = sub { |
|---|
| 60 | my $pwd = Cwd::cwd(); |
|---|
| 61 | if (my $code = $sym->{$pwd}) { |
|---|
| 62 | goto &$code unless $cwd eq $pwd; # delegate back to parent dirs |
|---|
| 63 | } |
|---|
| 64 | $$sym =~ /([^:]+)$/ or die "Cannot autoload $caller"; |
|---|
| 65 | unshift @_, ($self, $1); |
|---|
| 66 | goto &{$self->can('call')} unless uc($1) eq $1; |
|---|
| 67 | }; |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | use Cwd qw(cwd abs_path); |
|---|
| 71 | sub new { |
|---|
| 72 | my ($class, %args) = @_; |
|---|
| 73 | |
|---|
| 74 | # ignore the prefix on extension modules built from top level. |
|---|
| 75 | delete $args{prefix} |
|---|
| 76 | unless Cwd::abs_path(Cwd::cwd()) eq Cwd::abs_path($FindBin::Bin); |
|---|
| 77 | |
|---|
| 78 | return $args{_self} if $args{_self}; |
|---|
| 79 | |
|---|
| 80 | $args{dispatch} ||= 'Admin'; |
|---|
| 81 | $args{prefix} ||= 'inc'; |
|---|
| 82 | $args{author} ||= '.author'; |
|---|
| 83 | $args{bundle} ||= 'inc/BUNDLES'; |
|---|
| 84 | $args{base} ||= Cwd::abs_path($FindBin::Bin); |
|---|
| 85 | |
|---|
| 86 | $class =~ s/^inc:://; |
|---|
| 87 | $args{name} ||= $class; |
|---|
| 88 | $args{version} ||= $class->VERSION; |
|---|
| 89 | |
|---|
| 90 | unless ($args{path}) { |
|---|
| 91 | $args{path} = $args{name}; |
|---|
| 92 | $args{path} =~ s!::!/!g; |
|---|
| 93 | } |
|---|
| 94 | $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; |
|---|
| 95 | |
|---|
| 96 | bless(\%args, $class); |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | sub call { |
|---|
| 100 | my $self = shift; |
|---|
| 101 | my $method = shift; |
|---|
| 102 | my $obj = $self->load($method) or return; |
|---|
| 103 | |
|---|
| 104 | unshift @_, $obj; |
|---|
| 105 | goto &{$obj->can($method)}; |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | sub load { |
|---|
| 109 | my ($self, $method) = @_; |
|---|
| 110 | |
|---|
| 111 | my $extensions = $self->{extensions} || []; |
|---|
| 112 | unless (@$extensions) { |
|---|
| 113 | $self->load_extensions("$self->{prefix}/$self->{path}", $self); |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | foreach my $obj (@{$self->{extensions}}) { |
|---|
| 117 | return $obj if $obj->can($method); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | my $admin = $self->{admin} or die << "END"; |
|---|
| 121 | The '$method' method does not exist in the '$self->{prefix}' path! |
|---|
| 122 | Please remove the '$self->{prefix}' directory and run $0 again to load it. |
|---|
| 123 | END |
|---|
| 124 | |
|---|
| 125 | my $obj = $admin->load($method, 1); |
|---|
| 126 | push @{$self->{extensions}}, $obj; |
|---|
| 127 | |
|---|
| 128 | $obj; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | sub load_extensions { |
|---|
| 132 | my ($self, $path, $top_obj) = @_; |
|---|
| 133 | $path = "$self->{base}/$path"; |
|---|
| 134 | |
|---|
| 135 | unshift @INC, $self->{prefix} |
|---|
| 136 | unless grep { $_ eq $self->{prefix} } @INC; |
|---|
| 137 | |
|---|
| 138 | foreach my $rv ($self->find_extensions($path)) { |
|---|
| 139 | my ($file, $pkg) = @{$rv}; |
|---|
| 140 | next if $self->{pathnames}{$pkg}; |
|---|
| 141 | |
|---|
| 142 | eval { require $file; 1 } or (warn($@), next); |
|---|
| 143 | $self->{pathnames}{$pkg} = delete $INC{$file}; |
|---|
| 144 | push @{$self->{extensions}}, $pkg->new( _top => $top_obj ); |
|---|
| 145 | } |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | sub find_extensions { |
|---|
| 149 | my ($self, $path) = @_; |
|---|
| 150 | my @found; |
|---|
| 151 | |
|---|
| 152 | File::Find::find(sub { |
|---|
| 153 | my $file = $File::Find::name; |
|---|
| 154 | return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; |
|---|
| 155 | return if $1 eq $self->{dispatch}; |
|---|
| 156 | |
|---|
| 157 | $file = "$self->{path}/$1.pm"; |
|---|
| 158 | my $pkg = "$self->{name}::$1"; $pkg =~ s!/!::!g; |
|---|
| 159 | push @found, [$file, $pkg]; |
|---|
| 160 | }, $path) if -d $path; |
|---|
| 161 | |
|---|
| 162 | @found; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | 1; |
|---|
| 166 | |
|---|
| 167 | __END__ |
|---|