line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package OpenInteract::Startup; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# $Id: Startup.pm,v 1.37 2003/03/13 03:26:34 lachoy Exp $ |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
877
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
46
|
|
6
|
1
|
|
|
1
|
|
5
|
use Cwd qw( cwd ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
83
|
|
7
|
1
|
|
|
1
|
|
1093
|
use Data::Dumper qw( Dumper ); |
|
1
|
|
|
|
|
7078
|
|
|
1
|
|
|
|
|
87
|
|
8
|
1
|
|
|
1
|
|
11
|
use File::Basename qw( dirname ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
73
|
|
9
|
1
|
|
|
1
|
|
6
|
use File::Path qw(); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
18
|
|
10
|
1
|
|
|
1
|
|
1304
|
use Getopt::Long qw( GetOptions ); |
|
1
|
|
|
|
|
13756
|
|
|
1
|
|
|
|
|
9
|
|
11
|
1
|
|
|
1
|
|
762
|
use OpenInteract::Config; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
12
|
1
|
|
|
1
|
|
515
|
use OpenInteract::Config::GlobalOverride; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
35
|
|
13
|
1
|
|
|
1
|
|
8
|
use OpenInteract::Error; |
|
1
|
|
|
|
|
21
|
|
|
1
|
|
|
|
|
21
|
|
14
|
1
|
|
|
1
|
|
884
|
use OpenInteract::Package; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
use OpenInteract::PackageRepository; |
16
|
|
|
|
|
|
|
use SPOPS::ClassFactory; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
$OpenInteract::Startup::VERSION = sprintf("%d.%02d", q$Revision: 1.37 $ =~ /(\d+)\.(\d+)/); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use constant DEBUG => 0; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $TEMP_LIB_DIR = 'tmplib'; |
23
|
|
|
|
|
|
|
my $REPOS_CLASS = 'OpenInteract::PackageRepository'; |
24
|
|
|
|
|
|
|
my $PKG_CLASS = 'OpenInteract::Package'; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub main_initialize { |
27
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Ensure we can find the base configuration, and use it or read it in |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
return undef unless ( $p->{base_config} or $p->{base_config_file} ); |
32
|
|
|
|
|
|
|
my $bc = $p->{base_config} || |
33
|
|
|
|
|
|
|
$class->read_base_config({ filename => $p->{base_config_file} }); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Create our main config object |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my $C = $class->create_config({ base_config => $bc }); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Initialize the package repository class -- it's a SPOPS class, |
40
|
|
|
|
|
|
|
# but a really simple one |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
$REPOS_CLASS->class_initialize( $C ); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# Read in our fundamental modules -- these should be in our @INC |
45
|
|
|
|
|
|
|
# already, since the 'request_class' is in |
46
|
|
|
|
|
|
|
# 'OpenInteract/OpenInteract' and the 'stash_class' is in |
47
|
|
|
|
|
|
|
# 'MyApp/MyApp' |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
$class->require_module({ class => [ $bc->{request_class}, $bc->{stash_class} ] }); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Either use a package list provided or read in all the packages from |
52
|
|
|
|
|
|
|
# the website package database |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my $packages = []; |
55
|
|
|
|
|
|
|
my $repository = $REPOS_CLASS->fetch( undef, { directory => $bc->{website_dir} } ); |
56
|
|
|
|
|
|
|
if ( my $package_list = $p->{package_list} ) { |
57
|
|
|
|
|
|
|
foreach my $pkg_name ( @{ $p->{package_list} } ) { |
58
|
|
|
|
|
|
|
my $pkg_info = $repository->fetch_pacakge_by_name({ name => $pkg_name }); |
59
|
|
|
|
|
|
|
push @{ $packages }, $pkg_info if ( $pkg_info ); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
else { |
63
|
|
|
|
|
|
|
$packages = $repository->fetch_all_packages(); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# We keep track of the package names currently installed and use them |
67
|
|
|
|
|
|
|
# elsewhere in the system |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
$C->{package_list} = [ map { $_->{name} } @{ $packages } ]; |
70
|
|
|
|
|
|
|
foreach my $pkg_info ( @{ $packages } ) { |
71
|
|
|
|
|
|
|
$class->process_package( $pkg_info, $C ); |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
$class->_process_global_overrides( $C ); |
75
|
|
|
|
|
|
|
$class->_require_extra_classes( $C ); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Store the configuration for later use |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
my $stash_class = $bc->{stash_class}; |
80
|
|
|
|
|
|
|
$stash_class->set_stash( 'config', $C ); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Create an instance of $R since later steps might need it -- |
83
|
|
|
|
|
|
|
# particularly SPOPS initialization which may want a connection to |
84
|
|
|
|
|
|
|
# the datasource during setup. (Crossing fingers this doesn't mess |
85
|
|
|
|
|
|
|
# something up, particularly w/ parent/child sharing issues...) |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
my $request_class = $bc->{request_class}; |
88
|
|
|
|
|
|
|
my $R = $request_class->instance; |
89
|
|
|
|
|
|
|
$R->{stash_class} = $stash_class; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# The config object should now have all actions and SPOPS definitions |
92
|
|
|
|
|
|
|
# read in, so run any necessary configuration options |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my $init_class = $class->finalize_configuration({ config => $C }); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Tell OpenInteract::Request to setup aliases if they haven't already |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
if ( $p->{alias_init} ) { |
99
|
|
|
|
|
|
|
$request_class->setup_aliases; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Initialize all the SPOPS object classes |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
if ( $p->{spops_init} ) { |
105
|
|
|
|
|
|
|
$class->initialize_spops({ config => $C, class => $init_class }); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Read in all the classes for all configured conductors |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
my @conductor_classes = (); |
111
|
|
|
|
|
|
|
foreach my $conductor ( keys %{ $C->{conductor} } ) { |
112
|
|
|
|
|
|
|
push @conductor_classes, $C->{conductor}{ $conductor }{class}; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
$class->require_module({ class => \@conductor_classes }); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Read in the modules referred to in the 'system_alias' key from |
117
|
|
|
|
|
|
|
# the configuration -- EXCEPT for anything beginning with the |
118
|
|
|
|
|
|
|
# website name since that's an SPOPS object and has already been |
119
|
|
|
|
|
|
|
# created |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my @system_alias_classes = grep ! /^$bc->{website_name}/, values %{ $C->{system_alias} }; |
122
|
|
|
|
|
|
|
$class->require_module({ class => \@system_alias_classes }); |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
DEBUG && _w( 2, "Contents of INC: @INC" ); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# All done! Return the configuration object so the user can |
127
|
|
|
|
|
|
|
# do whatever else is necessary |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
return ( $init_class, $C ); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub setup_static_environment_options { |
134
|
|
|
|
|
|
|
my ( $class, $usage, $options, $params ) = @_; |
135
|
|
|
|
|
|
|
$options ||= {}; |
136
|
|
|
|
|
|
|
my ( $OPT_website_dir ); |
137
|
|
|
|
|
|
|
$options->{'website_dir=s'} = \$OPT_website_dir; |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# Get the options |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
GetOptions( %{ $options } ); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
if ( ! $OPT_website_dir and $ENV{OIWEBSITE} ) { |
144
|
|
|
|
|
|
|
warn "Using ($ENV{OIWEBSITE}) for 'website_dir'.\n"; |
145
|
|
|
|
|
|
|
$OPT_website_dir = $ENV{OIWEBSITE}; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
unless ( -d $OPT_website_dir ) { |
149
|
|
|
|
|
|
|
die "$usage\n Parameter 'website_dir' must refer to an OpenInteract website directory!\n"; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
return $class->setup_static_environment( $OPT_website_dir, undef, $params ); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Use this if you want to setup the OpenInteract environment outside |
156
|
|
|
|
|
|
|
# of the web application server -- just pass in the website directory! |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub setup_static_environment { |
159
|
|
|
|
|
|
|
my ( $class, $website_dir, $su_passwd, $params ) = @_; |
160
|
|
|
|
|
|
|
die "Directory ($website_dir) is not a valid directory!\n" unless ( -d $website_dir ); |
161
|
|
|
|
|
|
|
$params ||= {}; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
my $bc = $class->read_base_config({ dir => $website_dir }); |
164
|
|
|
|
|
|
|
unless ( $bc and ref $bc eq 'HASH' ) { |
165
|
|
|
|
|
|
|
die "No base configuration file found in website directory ($website_dir)" ; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
$class->create_temp_lib( $bc, $params->{temp_lib} ); |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
unshift @INC, $website_dir; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
my ( $init, $C ) = $class->main_initialize({ base_config => $bc, |
173
|
|
|
|
|
|
|
alias_init => 1, |
174
|
|
|
|
|
|
|
spops_init => 1 }); |
175
|
|
|
|
|
|
|
my $REQUEST_CLASS = $C->{server_info}{request_class}; |
176
|
|
|
|
|
|
|
my $R = $REQUEST_CLASS->instance; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
$R->{stash_class} = $C->{server_info}{stash_class}; |
179
|
|
|
|
|
|
|
$R->stash( 'config', $C ); |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# If we were given the superuser password, retrieve the user and |
182
|
|
|
|
|
|
|
# check the password |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
if ( $su_passwd ) { |
185
|
|
|
|
|
|
|
my $user = $R->user->fetch( 1, { skip_security => 1 }); |
186
|
|
|
|
|
|
|
die "Cannot create superuser!" unless ( $user ); |
187
|
|
|
|
|
|
|
unless ( $user->check_password( $su_passwd ) ) { |
188
|
|
|
|
|
|
|
die "Password for superuser does not match!\n"; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
$R->{auth}{user} = $user; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
return $R; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Slimmed down initialization procedure -- just do everything |
199
|
|
|
|
|
|
|
# necessary to read the config and set various values there |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub create_config { |
202
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
203
|
|
|
|
|
|
|
my $bc = $p->{base_config} || |
204
|
|
|
|
|
|
|
$class->read_base_config({ filename => $p->{base_config_file}, |
205
|
|
|
|
|
|
|
website_dir => $p->{website_dir} }); |
206
|
|
|
|
|
|
|
return undef unless ( $bc ); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Create the configuration file and set the base directory as configured; |
209
|
|
|
|
|
|
|
# also set other important classes from the config |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
my $config_file = join( '/', $bc->{website_dir}, |
212
|
|
|
|
|
|
|
$bc->{config_dir}, $bc->{config_file} ); |
213
|
|
|
|
|
|
|
my $C = eval { OpenInteract::Config->instance( $bc->{config_type}, $config_file ) }; |
214
|
|
|
|
|
|
|
if ( $@ ) { |
215
|
|
|
|
|
|
|
die "Cannot read configuration file! Error: $@\n"; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# This information will be set for the life of the config object, |
219
|
|
|
|
|
|
|
# which should be as long as the apache child is alive if we're using |
220
|
|
|
|
|
|
|
# mod_perl, and will be set in the returned config object in any case |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
$C->{dir}{base} = $bc->{website_dir}; |
223
|
|
|
|
|
|
|
$C->{dir}{interact} = $bc->{base_dir}; |
224
|
|
|
|
|
|
|
$C->{server_info}{request_class} = $bc->{request_class}; |
225
|
|
|
|
|
|
|
$C->{server_info}{stash_class} = $bc->{stash_class}; |
226
|
|
|
|
|
|
|
$C->{server_info}{website_name} = $bc->{website_name}; |
227
|
|
|
|
|
|
|
return $C; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Method to copy all .pm files from all packages in a website to a |
232
|
|
|
|
|
|
|
# separate directory -- if it currently exists we clear it out first. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub create_temp_lib { |
235
|
|
|
|
|
|
|
my ( $class, $base_config, $opt ) = @_; |
236
|
|
|
|
|
|
|
$opt ||= ''; |
237
|
|
|
|
|
|
|
my $site_dir = $base_config->{website_dir}; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
my $lib_dir = $base_config->{templib_dir} |
240
|
|
|
|
|
|
|
|| "$site_dir/$TEMP_LIB_DIR"; |
241
|
|
|
|
|
|
|
unshift @INC, $lib_dir; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
if ( -d $lib_dir and $opt eq 'lazy' ) { |
244
|
|
|
|
|
|
|
DEBUG && _w( 1, "Temp lib dir [$lib_dir] already exists and we're lazy;", |
245
|
|
|
|
|
|
|
"not copying modules to temp lib dir" ); |
246
|
|
|
|
|
|
|
return []; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
File::Path::rmtree( $lib_dir ) if ( -d $lib_dir ); |
250
|
|
|
|
|
|
|
mkdir( $lib_dir, 0777 ); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
my $site_repos = $REPOS_CLASS->fetch( undef, |
253
|
|
|
|
|
|
|
{ directory => $base_config->{website_dir} } ); |
254
|
|
|
|
|
|
|
my $packages = $site_repos->fetch_all_packages(); |
255
|
|
|
|
|
|
|
my ( @all_files ); |
256
|
|
|
|
|
|
|
foreach my $package ( @{ $packages } ) { |
257
|
|
|
|
|
|
|
DEBUG && _w( 2, "Trying to copy files for package $package->{name}" ); |
258
|
|
|
|
|
|
|
my $files_copied = $PKG_CLASS->copy_modules( $package, $lib_dir ); |
259
|
|
|
|
|
|
|
push @all_files, @{ $files_copied }; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
DEBUG && _w( 3, "Copied ", scalar @all_files, " module files to [$lib_dir]" ); |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Now change permissions so all the files and directories are |
264
|
|
|
|
|
|
|
# world-everything, letting the process's umask kick in |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
chmod( 0666, @all_files ); |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
my %tmp_dirs = map { $_ => 1 } map { dirname( $_ ) } @all_files; |
269
|
|
|
|
|
|
|
chmod( 0777, keys %tmp_dirs ); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
return \@all_files; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub read_package_list { |
276
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
277
|
|
|
|
|
|
|
return [] unless ( $p->{filename} or $p->{config} ); |
278
|
|
|
|
|
|
|
my $filename = $p->{filename} || |
279
|
|
|
|
|
|
|
join( '/', $p->{config}->get_dir( 'config' ), $p->{config}{package_list} ); |
280
|
|
|
|
|
|
|
open( PKG, $filename ) || die "Cannot open package list ($filename): $!"; |
281
|
|
|
|
|
|
|
my @packages = (); |
282
|
|
|
|
|
|
|
while ( ) { |
283
|
|
|
|
|
|
|
chomp; |
284
|
|
|
|
|
|
|
next if /^\s*\#/; |
285
|
|
|
|
|
|
|
next if /^\s*$/; |
286
|
|
|
|
|
|
|
s/^\s*//; |
287
|
|
|
|
|
|
|
s/\s*$//; |
288
|
|
|
|
|
|
|
push @packages, $_; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
close( PKG ); |
291
|
|
|
|
|
|
|
return \@packages; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# simple key-value config file |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub read_base_config { |
299
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
300
|
|
|
|
|
|
|
unless ( $p->{filename} ) { |
301
|
|
|
|
|
|
|
my $dir = $p->{dir} || $p->{website_dir}; |
302
|
|
|
|
|
|
|
if ( $dir ) { |
303
|
|
|
|
|
|
|
$p->{filename} = $class->create_base_config_filename( $dir ); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
return undef unless ( -f $p->{filename} ); |
307
|
|
|
|
|
|
|
open( CONF, $p->{filename} ) || die "$!\n"; |
308
|
|
|
|
|
|
|
my $vars = {}; |
309
|
|
|
|
|
|
|
while ( ) { |
310
|
|
|
|
|
|
|
chomp; |
311
|
|
|
|
|
|
|
DEBUG && _w( 1, "Config line read: $_" ); |
312
|
|
|
|
|
|
|
next if ( /^\s*\#/ ); |
313
|
|
|
|
|
|
|
next if ( /^\s*$/ ); |
314
|
|
|
|
|
|
|
s/^\s*//; |
315
|
|
|
|
|
|
|
s/\s*$//; |
316
|
|
|
|
|
|
|
my ( $var, $value ) = split /\s+/, $_, 2; |
317
|
|
|
|
|
|
|
$vars->{ $var } = $value; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
return $vars; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub create_base_config_filename { |
323
|
|
|
|
|
|
|
my ( $class, $dir ) = @_; |
324
|
|
|
|
|
|
|
return join( '/', $dir, 'conf', 'base.conf' ); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Params: |
328
|
|
|
|
|
|
|
# filename - file with modules to read, one per line (skip blanks, commented lines) |
329
|
|
|
|
|
|
|
# class - arrayref of classes to require |
330
|
|
|
|
|
|
|
# (pick one) |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub require_module { |
333
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
334
|
|
|
|
|
|
|
my @success = (); |
335
|
|
|
|
|
|
|
if ( $p->{filename} ) { |
336
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to open file $p->{filename}" ); |
337
|
|
|
|
|
|
|
return [] unless ( -f $p->{filename} ); |
338
|
|
|
|
|
|
|
open( MOD, $p->{filename} ) || die "Cannot open $p->{filename}: $!"; |
339
|
|
|
|
|
|
|
while ( ) { |
340
|
|
|
|
|
|
|
next if ( /^\s*$/ ); |
341
|
|
|
|
|
|
|
next if ( /^\s*\#/ ); |
342
|
|
|
|
|
|
|
chomp; |
343
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to require $_" ); |
344
|
|
|
|
|
|
|
eval "require $_"; |
345
|
|
|
|
|
|
|
if ( $@ ) { _w( 0, sprintf( " --require error: %-40s: %s", $_, $@ ) ) } |
346
|
|
|
|
|
|
|
else { push @success, $_ } |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
close( MOD ); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
elsif ( $p->{class} ) { |
351
|
|
|
|
|
|
|
$p->{class} = [ $p->{class} ] unless ( ref $p->{class} eq 'ARRAY' ); |
352
|
|
|
|
|
|
|
foreach ( @{ $p->{class} } ) { |
353
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to require class ($_)" ); |
354
|
|
|
|
|
|
|
eval "require $_"; |
355
|
|
|
|
|
|
|
if ( $@ ) { _w( 0, sprintf( " --require error: %-40s (from %s): %s", $_, $p->{pkg_link}{$_}, $@ ) ) } |
356
|
|
|
|
|
|
|
else { push @success, $_ } |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
return \@success; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# Params: |
365
|
|
|
|
|
|
|
# config = config object |
366
|
|
|
|
|
|
|
# package = name of package |
367
|
|
|
|
|
|
|
# package_dir = arrayref of base package directories (optional, read from config if not passed) |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub process_package { |
370
|
|
|
|
|
|
|
my ( $class, $pkg_info, $CONF ) = @_; |
371
|
|
|
|
|
|
|
return undef unless ( $pkg_info ); |
372
|
|
|
|
|
|
|
return undef unless ( $CONF ); |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
my $pkg_name = join( '-', $pkg_info->{name}, $pkg_info->{version} ); |
375
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to process package ($pkg_name)" ); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
my $site_pkg_dir = join( '/', $pkg_info->{website_dir}, $pkg_info->{package_dir} ); |
378
|
|
|
|
|
|
|
my $base_pkg_dir = join( '/', $pkg_info->{base_dir}, $pkg_info->{package_dir} ); |
379
|
|
|
|
|
|
|
DEBUG && _w( 1, "Pkg dirs: ($base_pkg_dir, $site_pkg_dir) for $pkg_name" ); |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# Plow through the directories and find the module listings (to |
382
|
|
|
|
|
|
|
# include), action config (to parse and set) and the SPOPS config (to |
383
|
|
|
|
|
|
|
# parse and set). Base package first so its info can be overridden. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
foreach my $package_dir ( $base_pkg_dir, $site_pkg_dir ) { |
386
|
|
|
|
|
|
|
my $conf_pkg_dir = "$package_dir/conf"; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# If the package does not have a 'list_module.dat', that's ok and the |
389
|
|
|
|
|
|
|
# 'require_module' class method will simply return an empty list. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
$class->require_module({ filename => "$conf_pkg_dir/list_module.dat" }); |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# Read in the 'action' information and set in the config object |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
$class->read_action_definition({ filename => "$conf_pkg_dir/action.perl", |
396
|
|
|
|
|
|
|
config => $CONF, |
397
|
|
|
|
|
|
|
package => $pkg_info }); |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# Read in the SPOPS information and set in the config object; note |
400
|
|
|
|
|
|
|
# that we cannot *process* the SPOPS config yet because we must be |
401
|
|
|
|
|
|
|
# able to relate SPOPS objects, which cannot be done until all the |
402
|
|
|
|
|
|
|
# definitions are read in. (Yes, we could use 'map' here and above, |
403
|
|
|
|
|
|
|
# but it's confusing to people first reading the code) |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
$class->read_spops_definition({ filename => "$conf_pkg_dir/spops.perl", |
406
|
|
|
|
|
|
|
config => $CONF, |
407
|
|
|
|
|
|
|
package => $pkg_info }); |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# Read in the action config info and set the information in the CONFIG |
414
|
|
|
|
|
|
|
# object. note that we overwrite whatever information is in the CONFIG |
415
|
|
|
|
|
|
|
# object -- this is a feature, not a bug, since it allows the base |
416
|
|
|
|
|
|
|
# installation to define lots of information and the website to only |
417
|
|
|
|
|
|
|
# override what it needs. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# Also save the key under which this was retrieved under 'key' |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub read_action_definition { |
422
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
423
|
|
|
|
|
|
|
DEBUG && _w( 1, "Reading action definitions from ($p->{filename})" ); |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# $CONF is easier to read and more consistent |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
my $CONF = $p->{config}; |
428
|
|
|
|
|
|
|
my $action_info = eval { $class->read_perl_file({ filename => $p->{filename} }) }; |
429
|
|
|
|
|
|
|
return undef unless ( $action_info ); |
430
|
|
|
|
|
|
|
my @class_list = (); |
431
|
|
|
|
|
|
|
foreach my $action_key ( keys %{ $action_info } ) { |
432
|
|
|
|
|
|
|
$CONF->{action}{ $action_key }{key} = $action_key; |
433
|
|
|
|
|
|
|
foreach my $action_conf ( keys %{ $action_info->{ $action_key } } ) { |
434
|
|
|
|
|
|
|
$CONF->{action}{ $action_key }{ $action_conf } = |
435
|
|
|
|
|
|
|
$action_info->{ $action_key }{ $action_conf }; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
if ( ref $p->{package} ) { |
438
|
|
|
|
|
|
|
$CONF->{action}{ $action_key }{package_name} = $p->{package}{name}; |
439
|
|
|
|
|
|
|
$CONF->{action}{ $action_key }{package_version} = $p->{package}{version}; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# See comments in read_action_definition |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
sub read_spops_definition { |
449
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
450
|
|
|
|
|
|
|
DEBUG && _w( 1, "Reading SPOPS definitions from ($p->{filename})" ); |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# $CONF is easier to read and more consistent |
453
|
|
|
|
|
|
|
my $CONF = $p->{config}; |
454
|
|
|
|
|
|
|
my $spops_info = eval { $class->read_perl_file({ filename => $p->{filename} }) }; |
455
|
|
|
|
|
|
|
return undef unless ( $spops_info ); |
456
|
|
|
|
|
|
|
my @class_list = (); |
457
|
|
|
|
|
|
|
foreach my $spops_key ( keys %{ $spops_info } ) { |
458
|
|
|
|
|
|
|
$CONF->{SPOPS}{ $spops_key }{key} = $spops_key; |
459
|
|
|
|
|
|
|
foreach my $spops_conf ( keys %{ $spops_info->{ $spops_key } } ) { |
460
|
|
|
|
|
|
|
$CONF->{SPOPS}{ $spops_key }{ $spops_conf } = |
461
|
|
|
|
|
|
|
$spops_info->{ $spops_key }{ $spops_conf }; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
if ( ref $p->{package} ) { |
464
|
|
|
|
|
|
|
$CONF->{SPOPS}{ $spops_key }{package_name} = $p->{package}{name}; |
465
|
|
|
|
|
|
|
$CONF->{SPOPS}{ $spops_key }{package_version} = $p->{package}{version}; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Read in a perl structure (probably generated by Data::Dumper) from a |
472
|
|
|
|
|
|
|
# file and return the actual structure. We should probably use |
473
|
|
|
|
|
|
|
# SPOPS::HashFile for this for consistency... |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
sub read_perl_file { |
476
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
477
|
|
|
|
|
|
|
return undef unless ( -f $p->{filename} ); |
478
|
|
|
|
|
|
|
eval { open( INFO, $p->{filename} ) || die $! }; |
479
|
|
|
|
|
|
|
if ( $@ ) { |
480
|
|
|
|
|
|
|
warn "Cannot open config file for evaluation ($p->{filename}): $@ "; |
481
|
|
|
|
|
|
|
return undef; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
local $/ = undef; |
484
|
|
|
|
|
|
|
no strict; |
485
|
|
|
|
|
|
|
my $info = ; |
486
|
|
|
|
|
|
|
close( INFO ); |
487
|
|
|
|
|
|
|
my $data = eval $info; |
488
|
|
|
|
|
|
|
if ( $@ ) { |
489
|
|
|
|
|
|
|
die "Cannot read data structure! from $p->{filename}\nError: $@"; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
return $data; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# Everything has been read in, now just finalize aliases and so on |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub finalize_configuration { |
498
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
499
|
|
|
|
|
|
|
my $CONF = $p->{config}; |
500
|
|
|
|
|
|
|
my $REQUEST_CLASS = $CONF->{server_info}{request_class}; |
501
|
|
|
|
|
|
|
my $STASH_CLASS = $CONF->{server_info}{stash_class}; |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# Create all the packages and subroutines on the fly as necessary |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to configure SPOPS classes with SPOPS::ClassFactory" ); |
506
|
|
|
|
|
|
|
my $init_class = SPOPS::ClassFactory->create( $CONF->{SPOPS} ); |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
# Setup the default responses, template classes, etc. for all the |
509
|
|
|
|
|
|
|
# actions read in. |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
$CONF->flatten_action_config; |
512
|
|
|
|
|
|
|
DEBUG && _w( 2, "Config: \n", Dumper( $CONF ) ); |
513
|
|
|
|
|
|
|
DEBUG && _w( 1, "Configuration read into Request ok." ); |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# We also want to go through each alias in the 'SPOPS' config key |
516
|
|
|
|
|
|
|
# and setup aliases to the proper class within our Request class; so |
517
|
|
|
|
|
|
|
# $request_alias is just a reference to where we'll actually be storing |
518
|
|
|
|
|
|
|
# this stuff |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
my $request_alias = $REQUEST_CLASS->ALIAS; |
521
|
|
|
|
|
|
|
DEBUG && _w( 1, "Setting up SPOPS aliases" ); |
522
|
|
|
|
|
|
|
foreach my $init_alias ( keys %{ $CONF->{SPOPS} } ) { |
523
|
|
|
|
|
|
|
next if ( $init_alias =~ /^_/ ); |
524
|
|
|
|
|
|
|
my $info = $CONF->{SPOPS}{ $init_alias }; |
525
|
|
|
|
|
|
|
my $class_alias = $info->{class}; |
526
|
|
|
|
|
|
|
my @alias_list = ( $init_alias ); |
527
|
|
|
|
|
|
|
push @alias_list, @{ $info->{alias} } if ( $info->{alias} ); |
528
|
|
|
|
|
|
|
foreach my $alias ( @alias_list ) { |
529
|
|
|
|
|
|
|
DEBUG && _w( 1, "Tag $alias in $STASH_CLASS to be $class_alias" ); |
530
|
|
|
|
|
|
|
$request_alias->{ $alias }{ $STASH_CLASS } = $class_alias; |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
DEBUG && _w( 1, "Setting up System aliases" ); |
535
|
|
|
|
|
|
|
foreach my $alias ( keys %{ $CONF->{system_alias} } ) { |
536
|
|
|
|
|
|
|
$request_alias->{ $alias }{ $STASH_CLASS } = $CONF->{system_alias}{ $alias }; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
DEBUG && _w( 1, "Setup object and system aliases ok" ); |
539
|
|
|
|
|
|
|
return $init_class; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# Plow through a list of classes and call the class_initialize |
544
|
|
|
|
|
|
|
# method on each; ok to call OpenInteract::Startup->initialize_spops( ... ) |
545
|
|
|
|
|
|
|
# from the mod_perl child init handler |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
sub initialize_spops { |
548
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
549
|
|
|
|
|
|
|
return undef unless ( ref $p->{class} ); |
550
|
|
|
|
|
|
|
return undef unless ( ref $p->{config} ); |
551
|
|
|
|
|
|
|
my @success = (); |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# Just cycle through and initialize each |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
foreach my $spops_class ( @{ $p->{class} } ) { |
556
|
|
|
|
|
|
|
eval { $spops_class->class_initialize( $p->{config} ); }; |
557
|
|
|
|
|
|
|
push @success, $spops_class unless ( $@ ); |
558
|
|
|
|
|
|
|
DEBUG && _w( 1, sprintf( "%-40s: %-30s","init: $spops_class", ( $@ ) ? $@ : 'ok' ) ); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
return \@success; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# Do any global overrides for both SPOPS and the action table entries. |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub _process_global_overrides { |
567
|
|
|
|
|
|
|
my ( $class, $config ) = @_; |
568
|
|
|
|
|
|
|
my $override_spops_file = join( '/', $config->{dir}{base}, |
569
|
|
|
|
|
|
|
$config->{override}{spops_file} ); |
570
|
|
|
|
|
|
|
my $override_action_file = join( '/', $config->{dir}{base}, |
571
|
|
|
|
|
|
|
$config->{override}{action_file} ); |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
if ( -f $override_spops_file ) { |
574
|
|
|
|
|
|
|
my $override_spops = OpenInteract::Config::GlobalOverride->new( |
575
|
|
|
|
|
|
|
{ filename => $override_spops_file } ); |
576
|
|
|
|
|
|
|
$override_spops->apply_rules( $config->{SPOPS} ); |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
if ( -f $override_action_file ) { |
579
|
|
|
|
|
|
|
my $override_action = OpenInteract::Config::GlobalOverride->new( |
580
|
|
|
|
|
|
|
{ filename => $override_action_file } ); |
581
|
|
|
|
|
|
|
$override_action->apply_rules( $config->{action} ); |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
sub _require_extra_classes { |
587
|
|
|
|
|
|
|
my ( $class, $config ) = @_; |
588
|
|
|
|
|
|
|
my ( %require_class ); |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
my $action_require = $class->_find_extra_action_classes( $config ); |
591
|
|
|
|
|
|
|
my $spops_require = $class->_find_extra_spops_classes( $config ); |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Read in all the classes specified by the packages |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
my $successful_action = $class->require_module({ |
596
|
|
|
|
|
|
|
class => [ keys %{ $action_require } ], |
597
|
|
|
|
|
|
|
pkg_link => $action_require }); |
598
|
|
|
|
|
|
|
if ( scalar @{ $successful_action } != scalar keys %{ $action_require } ) { |
599
|
|
|
|
|
|
|
my %all_tried = map { $_ => 1 } keys %{ $action_require }; |
600
|
|
|
|
|
|
|
delete $all_tried{ $_ } for ( @{ $successful_action } ); |
601
|
|
|
|
|
|
|
_w( 0, "Some action classes were not required: ", |
602
|
|
|
|
|
|
|
join( ', ', keys %all_tried ) ); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
my $successful_spops = $class->require_module({ |
606
|
|
|
|
|
|
|
class => [ keys %{ $spops_require } ], |
607
|
|
|
|
|
|
|
pkg_link => $spops_require }); |
608
|
|
|
|
|
|
|
if ( scalar @{ $successful_spops } != scalar keys %{ $spops_require } ) { |
609
|
|
|
|
|
|
|
my %all_tried = map { $_ => 1 } keys %{ $spops_require }; |
610
|
|
|
|
|
|
|
delete $all_tried{ $_ } for ( @{ $successful_spops } ); |
611
|
|
|
|
|
|
|
_w( 0, "Some SPOPS classes were not required: ", |
612
|
|
|
|
|
|
|
join( ', ', keys %all_tried ) ); |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
sub _find_extra_action_classes { |
618
|
|
|
|
|
|
|
my ( $class, $config ) = @_; |
619
|
|
|
|
|
|
|
my %map = (); |
620
|
|
|
|
|
|
|
my $action = $config->{action}; |
621
|
|
|
|
|
|
|
foreach my $key ( keys %{ $action } ) { |
622
|
|
|
|
|
|
|
next unless ( $key and $action->{ $key }); |
623
|
|
|
|
|
|
|
my $package = $action->{ $key }{package_name}; |
624
|
|
|
|
|
|
|
if ( $action->{ $key }{class} ) { |
625
|
|
|
|
|
|
|
$map{ $action->{ $key }{class} } = $package |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
if ( $action->{ $key }{filter} ) { |
628
|
|
|
|
|
|
|
if ( ref $action->{ $key }{filter} eq 'ARRAY' ) { |
629
|
|
|
|
|
|
|
$map{ $_ } = $package for ( @{ $action->{ $key }{filter} } ); |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
else { |
632
|
|
|
|
|
|
|
$map{ $action->{ $key }{filter} } = $package |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
if ( $action->{ $key }{error} ) { |
636
|
|
|
|
|
|
|
if ( ref $action->{ $key }{error} eq 'ARRAY' ) { |
637
|
|
|
|
|
|
|
$map{ $_ } = $package for ( @{ $action->{ $key }{error} } ); |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
else { |
640
|
|
|
|
|
|
|
$map{ $action->{ $key }{error} } = $package; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
return \%map; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
sub _find_extra_spops_classes { |
649
|
|
|
|
|
|
|
my ( $class, $config ) = @_; |
650
|
|
|
|
|
|
|
my %map = (); |
651
|
|
|
|
|
|
|
my $spops = $config->{SPOPS}; |
652
|
|
|
|
|
|
|
foreach my $key ( keys %{ $spops } ) { |
653
|
|
|
|
|
|
|
next unless ( $key and $spops->{ $key }); |
654
|
|
|
|
|
|
|
my $package = $spops->{ $key }{package_name}; |
655
|
|
|
|
|
|
|
if ( ref $spops->{ $key }{isa} eq 'ARRAY' ) { |
656
|
|
|
|
|
|
|
map { $map{ $_ } = $package } @{ $spops->{ $key }{isa} }; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
return \%map; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
sub _w { |
665
|
|
|
|
|
|
|
return unless ( DEBUG >= shift ); |
666
|
|
|
|
|
|
|
my ( $pkg, $file, $line ) = caller; |
667
|
|
|
|
|
|
|
my @ci = caller(1); |
668
|
|
|
|
|
|
|
warn "$ci[3] ($line) >> ", join( ' ', @_ ), "\n"; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
1; |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
__END__ |