| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package OpenInteract::Package; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# $Id: Package.pm,v 1.40 2003/01/25 16:16:07 lachoy Exp $ |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# This module manipulates information from individual packages to |
|
6
|
|
|
|
|
|
|
# perform some action in the package files. |
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
6
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
34
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
1227
|
use Archive::Tar (); |
|
|
1
|
|
|
|
|
380322
|
|
|
|
1
|
|
|
|
|
32
|
|
|
11
|
1
|
|
|
1
|
|
14
|
use Cwd qw( cwd ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
74
|
|
|
12
|
1
|
|
|
1
|
|
6
|
use Data::Dumper qw( Dumper ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
49
|
|
|
13
|
1
|
|
|
1
|
|
3264
|
use ExtUtils::Manifest (); |
|
|
1
|
|
|
|
|
17006
|
|
|
|
1
|
|
|
|
|
30
|
|
|
14
|
1
|
|
|
1
|
|
11
|
use File::Basename (); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
20
|
|
|
15
|
1
|
|
|
1
|
|
5
|
use File::Copy qw( cp ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
63
|
|
|
16
|
1
|
|
|
1
|
|
5
|
use File::Path (); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
15
|
|
|
17
|
1
|
|
|
1
|
|
541
|
use SPOPS::HashFile (); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use SPOPS::Utility (); |
|
19
|
|
|
|
|
|
|
require Exporter; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
@OpenInteract::Package::ISA = qw( Exporter ); |
|
22
|
|
|
|
|
|
|
$OpenInteract::Package::VERSION = sprintf("%d.%02d", q$Revision: 1.40 $ =~ /(\d+)\.(\d+)/); |
|
23
|
|
|
|
|
|
|
@OpenInteract::Package::EXPORT_OK = qw( READONLY_FILE ); |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use constant READONLY_FILE => '.no_overwrite'; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Define the subdirectories present in a package |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my @PKG_SUBDIR = qw( conf data doc struct template script html html/images ); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Fields in our package/configuration |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my @PKG_FIELDS = qw( name version author url description notes |
|
34
|
|
|
|
|
|
|
module template_plugin template_block filter |
|
35
|
|
|
|
|
|
|
base_dir website_dir package_dir website_name |
|
36
|
|
|
|
|
|
|
dependency script_install script_upgrade |
|
37
|
|
|
|
|
|
|
script_uninstall sql_installer installed_on |
|
38
|
|
|
|
|
|
|
installed_by last_updated_on last_updated_by ); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Name of the package configuration file, always found in the |
|
42
|
|
|
|
|
|
|
# package's root directory |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $DEFAULT_CONF_FILE = 'package.conf'; |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Define the keys in 'package.conf' that can be a list, meaning you |
|
47
|
|
|
|
|
|
|
# can have multiple items defined: |
|
48
|
|
|
|
|
|
|
# |
|
49
|
|
|
|
|
|
|
# author Larry Wall |
|
50
|
|
|
|
|
|
|
# author Chris Winters |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my %CONF_LIST_KEYS = map { $_ => 1 } |
|
53
|
|
|
|
|
|
|
qw( author script_install script_upgrade script_uninstall module ); |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# Define the keys in 'package.conf' that can be a hash, meaning that |
|
56
|
|
|
|
|
|
|
# you can have items defined as multiple key-value pairs |
|
57
|
|
|
|
|
|
|
# (space-separated): |
|
58
|
|
|
|
|
|
|
# |
|
59
|
|
|
|
|
|
|
# dependency base_linked 1.09 |
|
60
|
|
|
|
|
|
|
# dependency static_page 1.18 |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my %CONF_HASH_KEYS = map { $_ => 1 } qw( dependency template_plugin template_block filter ); |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# For exporting a package, the following variables are required in |
|
65
|
|
|
|
|
|
|
# 'package.conf' |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my @EXPORT_REQUIRED = qw( name version ); |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Global for holding Archive::Tar errors |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
my $ARCHIVE_ERROR = undef; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Fields NOT to copy over in conf/spops.perl when creating package in |
|
74
|
|
|
|
|
|
|
# website from base installation (the first three are ones we |
|
75
|
|
|
|
|
|
|
# manipulate by hand) |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my %SPOPS_CONF_KEEP = map { $_ => 1 } qw( class has_a links_to ); |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# These are the default public and site admin group IDs; we use them |
|
80
|
|
|
|
|
|
|
# when copying over the SPOPS configuration files (see |
|
81
|
|
|
|
|
|
|
# _copy_spops_config_file()) |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
use constant PUBLIC_GROUP_ID => 2; |
|
84
|
|
|
|
|
|
|
use constant SITE_ADMIN_GROUP_ID => 3; |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
use constant DEBUG => 0; |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Create subdirectories for a package. |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub create_subdirectories { |
|
92
|
|
|
|
|
|
|
my ( $class, $dir, $main_class ) = @_; |
|
93
|
|
|
|
|
|
|
$main_class ||= 'OpenInteract'; |
|
94
|
|
|
|
|
|
|
return undef unless ( -d $dir ); |
|
95
|
|
|
|
|
|
|
foreach my $sub_dir ( @PKG_SUBDIR, $main_class, |
|
96
|
|
|
|
|
|
|
"$main_class/Handler", |
|
97
|
|
|
|
|
|
|
"$main_class/SQLInstall" ) { |
|
98
|
|
|
|
|
|
|
mkdir( "$dir/$sub_dir", 0775 ) |
|
99
|
|
|
|
|
|
|
|| die "Cannot create package subdirectory $dir/$sub_dir: $!"; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
return 1; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Creates a package directories using our base subdirectories |
|
106
|
|
|
|
|
|
|
# along with a package.conf file and some other goodies (?) |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub create_skeleton { |
|
109
|
|
|
|
|
|
|
my ( $class, $repository, $name ) = @_; |
|
110
|
|
|
|
|
|
|
my $pwd = cwd; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my $cleaned_pkg = $class->_clean_package_name( $name ); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Check directories |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
unless ( $repository ) { |
|
117
|
|
|
|
|
|
|
die "Cannot create package skeleton: no existing base ", |
|
118
|
|
|
|
|
|
|
"installation repository specified!\n"; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my $base_dir = $repository->{META_INF}{base_dir}; |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
if ( -d $cleaned_pkg ) { |
|
124
|
|
|
|
|
|
|
die "Cannot create package skeleton: directory ($cleaned_pkg) already exists!\n"; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
mkdir( $cleaned_pkg, 0775 ) || die "Cannot create package directory $cleaned_pkg: $!\n"; |
|
127
|
|
|
|
|
|
|
chdir( $cleaned_pkg ); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Then create the subdirectories for the package |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
$class->create_subdirectories( '.' ); |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# This does a replacement so that 'static_page' becomes StaticPage |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
my $uc_first_name = ucfirst $cleaned_pkg; |
|
136
|
|
|
|
|
|
|
$uc_first_name =~ s/_(\w)/\U$1\U/g; |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Copy over files from the samples (located in the base OpenInteract |
|
139
|
|
|
|
|
|
|
# directory), doing replacements as necessary |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
$class->replace_and_copy({ from_file => "$base_dir/conf/sample-package.conf", |
|
142
|
|
|
|
|
|
|
to_file => "package.conf", |
|
143
|
|
|
|
|
|
|
from_text => [ '%%NAME%%', '%%UC_FIRST_NAME%%' ], |
|
144
|
|
|
|
|
|
|
to_text => [ $cleaned_pkg, $uc_first_name ] }); |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
$class->replace_and_copy({ from_file => "$base_dir/conf/sample-package.pod", |
|
147
|
|
|
|
|
|
|
to_file => "doc/$cleaned_pkg.pod", |
|
148
|
|
|
|
|
|
|
from_text => [ '%%NAME%%' ], |
|
149
|
|
|
|
|
|
|
to_text => [ $cleaned_pkg ] }); |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
$class->replace_and_copy({ from_file => "$base_dir/conf/sample-doc-titles", |
|
152
|
|
|
|
|
|
|
to_file => "doc/titles", |
|
153
|
|
|
|
|
|
|
from_text => [ '%%NAME%%' ], |
|
154
|
|
|
|
|
|
|
to_text => [ $cleaned_pkg ] }); |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
$class->replace_and_copy({ from_file => "$base_dir/conf/sample-SQLInstall.pm", |
|
157
|
|
|
|
|
|
|
to_file => "OpenInteract/SQLInstall/$uc_first_name.pm", |
|
158
|
|
|
|
|
|
|
from_text => [ '%%NAME%%', '%%UC_FIRST_NAME%%' ], |
|
159
|
|
|
|
|
|
|
to_text => [ $cleaned_pkg, $uc_first_name ] }); |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
$class->replace_and_copy({ from_file => "$base_dir/conf/sample-Handler.pm", |
|
162
|
|
|
|
|
|
|
to_file => "OpenInteract/Handler/$uc_first_name.pm", |
|
163
|
|
|
|
|
|
|
from_text => [ '%%NAME%%', '%%UC_FIRST_NAME%%' ], |
|
164
|
|
|
|
|
|
|
to_text => [ $cleaned_pkg, $uc_first_name ] }); |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
cp( "$base_dir/conf/sample-spops.perl", "conf/spops.perl" ) |
|
167
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy sample (conf/spops.perl): $!" ); |
|
168
|
|
|
|
|
|
|
cp( "$base_dir/conf/sample-action.perl", "conf/action.perl" ) |
|
169
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy sample (conf/action.perl): $!" ); |
|
170
|
|
|
|
|
|
|
cp( "$base_dir/conf/sample-MANIFEST.SKIP", "MANIFEST.SKIP" ) |
|
171
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy sample (MANIFEST.SKIP): $!" ); |
|
172
|
|
|
|
|
|
|
cp( "$base_dir/conf/sample-dummy-template.meta", "template/dummy.meta" ) |
|
173
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy sample (template/dummy.meta): $!" ); |
|
174
|
|
|
|
|
|
|
cp( "$base_dir/conf/sample-dummy-template.tmpl", "template/dummy.tmpl" ) |
|
175
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy sample (template/dummy.tmpl): $!" ); |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# Create a 'Changes' file |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
eval { open( CHANGES, "> Changes" ) || die $! }; |
|
180
|
|
|
|
|
|
|
if ( $@ ) { |
|
181
|
|
|
|
|
|
|
_w( 0, "Cannot open 'Changes' file ($!). Please create your ", |
|
182
|
|
|
|
|
|
|
"own so people can follow your progress." ); |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
else { |
|
185
|
|
|
|
|
|
|
my $time_stamp = scalar localtime; |
|
186
|
|
|
|
|
|
|
print CHANGES <
|
|
187
|
|
|
|
|
|
|
Revision history for OpenInteract package $cleaned_pkg. |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
0.01 $time_stamp |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Package skeleton created by oi_manage |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
INIT |
|
194
|
|
|
|
|
|
|
close( CHANGES ); |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Create a MANIFEST from the pwd |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
$class->_create_manifest(); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# Go back to the original dir and return the name |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
chdir( $pwd ); |
|
204
|
|
|
|
|
|
|
return $cleaned_pkg; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Rules for a clean package name: |
|
209
|
|
|
|
|
|
|
# - Package name cannot have spaces (s/ /_/) |
|
210
|
|
|
|
|
|
|
# - Package name cannot have dashes (s/-/_/) |
|
211
|
|
|
|
|
|
|
# - Package name cannot start with a number (die) |
|
212
|
|
|
|
|
|
|
# - Package name cannot have nonword characters except '_' |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub _clean_package_name { |
|
215
|
|
|
|
|
|
|
my ( $class, $name ) = @_; |
|
216
|
|
|
|
|
|
|
my ( @clean_actions, @die_actions ); |
|
217
|
|
|
|
|
|
|
$name =~ s/ /_/g && push @clean_actions, "Name must not have spaces"; |
|
218
|
|
|
|
|
|
|
$name =~ s/\-/_/g && push @clean_actions, "Name must not have dashes"; |
|
219
|
|
|
|
|
|
|
$name =~ /^\d/ && push @die_actions, "Name must not start with a number"; |
|
220
|
|
|
|
|
|
|
$name =~ /\W/ && push @die_actions, "Name must not have non-word characters"; |
|
221
|
|
|
|
|
|
|
if ( scalar @die_actions ) { |
|
222
|
|
|
|
|
|
|
die "Package name unacceptable: \n", |
|
223
|
|
|
|
|
|
|
join( "\n", @die_actions, @clean_actions ), "\n"; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
return $name; |
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Takes a package file and installs the package to the base |
|
230
|
|
|
|
|
|
|
# OpenInteract directory. |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub install_distribution { |
|
233
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
|
234
|
|
|
|
|
|
|
my $old_pwd = cwd; |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# ------------------------------ |
|
237
|
|
|
|
|
|
|
# Taken from CGI.pm |
|
238
|
|
|
|
|
|
|
# FIGURE OUT THE OS WE'RE RUNNING UNDER |
|
239
|
|
|
|
|
|
|
# Some systems support the $^O variable. If not |
|
240
|
|
|
|
|
|
|
# available then require() the Config library |
|
241
|
|
|
|
|
|
|
my $OS = undef; |
|
242
|
|
|
|
|
|
|
unless ( $OS = $^O ) { |
|
243
|
|
|
|
|
|
|
require Config; |
|
244
|
|
|
|
|
|
|
$OS = $Config::Config{'osname'}; |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
# ------------------------------ |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
unless ( -f $p->{package_file} ) { |
|
249
|
|
|
|
|
|
|
die "Package file for installation ($p->{package_file}) does not exist\n"; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# TODO: Use File::Spec for this? |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Note that this should NOT be just 'win' since 'Darwin' gives a |
|
255
|
|
|
|
|
|
|
# (very) false positive |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
if ( $OS =~ /Win32/i ) { |
|
258
|
|
|
|
|
|
|
unless ( $p->{package_file} =~ /^\w:\// ) { |
|
259
|
|
|
|
|
|
|
$p->{package_file} = join( '/', $old_pwd, $p->{package_file} ); |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
else { |
|
263
|
|
|
|
|
|
|
unless ( $p->{package_file} =~ /^\// ) { |
|
264
|
|
|
|
|
|
|
$p->{package_file} = join( '/', $old_pwd, $p->{package_file} ); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
DEBUG && _w( 1, "Package file used for distribution: ($p->{package_file}" ); |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# This is the repository we'll be using |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
my $repos = $p->{repository} || |
|
272
|
|
|
|
|
|
|
eval { OpenInteract::PackageRepository->fetch( |
|
273
|
|
|
|
|
|
|
undef, { directory => $p->{base_dir}, |
|
274
|
|
|
|
|
|
|
perm => 'write' } ) }; |
|
275
|
|
|
|
|
|
|
unless ( $repos ) { die "Cannot open repository: $@\n" } |
|
276
|
|
|
|
|
|
|
my $base_dir = $repos->{META_INF}{base_dir}; |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
my $base_package_file = File::Basename::basename( $p->{package_file} ); |
|
279
|
|
|
|
|
|
|
my ( $package_base ) = $base_package_file =~ /^(.*)\.tar\.gz$/; |
|
280
|
|
|
|
|
|
|
DEBUG && _w( 1, "Package base: $package_base" ); |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
my $rv = $class->_extract_archive( $p->{package_file} ); |
|
283
|
|
|
|
|
|
|
unless ( $rv ) { |
|
284
|
|
|
|
|
|
|
my $msg = "Error found trying to unpack the distribution! " . |
|
285
|
|
|
|
|
|
|
"Error: " . $ARCHIVE_ERROR; |
|
286
|
|
|
|
|
|
|
my $removed_files = $class->_remove_directory_tree( $package_base ); |
|
287
|
|
|
|
|
|
|
die $msg; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Read in the package config and grab the name/version |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
chdir( $package_base ); |
|
293
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to find config file in ($package_base/)" ); |
|
294
|
|
|
|
|
|
|
my $conf_file = $p->{package_conf_file} || $DEFAULT_CONF_FILE; |
|
295
|
|
|
|
|
|
|
my $conf = $class->read_config({ file => $conf_file }); |
|
296
|
|
|
|
|
|
|
die "No valid package config read!\n" unless ( scalar keys %{ $conf } ); |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
my $name = $conf->{name}; |
|
299
|
|
|
|
|
|
|
my $version = $conf->{version}; |
|
300
|
|
|
|
|
|
|
chdir( $old_pwd ); |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# We're all done with the temp stuff, so get rid of it. |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
my $removed_files = $class->_remove_directory_tree( $package_base ); |
|
305
|
|
|
|
|
|
|
DEBUG && _w( 2, "Removed extracted tree, config file found ok." ); |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# Check to see if the package/version already exists |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
my $error_msg = undef; |
|
310
|
|
|
|
|
|
|
my $exist_info = $repos->fetch_package_by_name({ name => $name, |
|
311
|
|
|
|
|
|
|
version => $version }); |
|
312
|
|
|
|
|
|
|
if ( $exist_info ) { |
|
313
|
|
|
|
|
|
|
die "Cannot install since package $name-$version already " . |
|
314
|
|
|
|
|
|
|
"exists in the base installation repository. (It was installed on " . |
|
315
|
|
|
|
|
|
|
"$exist_info->{installed_on}).\n\nAborting package installation.\n"; |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
DEBUG && _w( 1, "Package does not currently exist in repository." ); |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Now see if the package has specified any modules that are |
|
320
|
|
|
|
|
|
|
# necessary for its operation. For now, we will refuse to install |
|
321
|
|
|
|
|
|
|
# a package that does not have supporting modules. |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
if ( ref $conf->{module} eq 'ARRAY' ) { |
|
324
|
|
|
|
|
|
|
my @failed_modules = $class->_check_module_install( @{ $conf->{module} } ); |
|
325
|
|
|
|
|
|
|
if ( scalar @failed_modules ) { |
|
326
|
|
|
|
|
|
|
die "Package $name-$version requires the following modules " . |
|
327
|
|
|
|
|
|
|
"that are not currently installed: " . join( ', ', @failed_modules ) . |
|
328
|
|
|
|
|
|
|
". Please install them and try again.\n"; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# Create some directory names and move to the base package directory |
|
333
|
|
|
|
|
|
|
# -- the directory that holds all of the package definitions |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my $new_pkg_dir = join( '/', 'pkg', "$name-$version" ); |
|
336
|
|
|
|
|
|
|
my $full_pkg_dir = join( '/', $base_dir, $new_pkg_dir ); |
|
337
|
|
|
|
|
|
|
if ( -d $full_pkg_dir ) { |
|
338
|
|
|
|
|
|
|
die "The directory into which the distribution should be unpacked ", |
|
339
|
|
|
|
|
|
|
"($full_pkg_dir) already exists. Please remove it and try again.\n"; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
chdir( join( '/', $base_dir, 'pkg' ) ); |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# Unarchive the package; note that since the archive creates a |
|
344
|
|
|
|
|
|
|
# directory name-version/blah we don't need to create the directory |
|
345
|
|
|
|
|
|
|
# ourselves and then chdir() to it. |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
my $extract_rv = $class->_extract_archive( $p->{package_file} ); |
|
348
|
|
|
|
|
|
|
unless ( $extract_rv ) { |
|
349
|
|
|
|
|
|
|
chdir( $base_dir ); |
|
350
|
|
|
|
|
|
|
$class->_remove_directory_tree( $full_pkg_dir ); |
|
351
|
|
|
|
|
|
|
die "Cannot unpack the distribution into its final " . |
|
352
|
|
|
|
|
|
|
"directory ($full_pkg_dir)! Error: " . $ARCHIVE_ERROR; |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
DEBUG && _w( 1, "Unpackaged package into $base_dir/pkg ok" ); |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Create the package info and try to save; if we're successful, return the |
|
357
|
|
|
|
|
|
|
# package info. |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
my $info = { |
|
360
|
|
|
|
|
|
|
base_dir => $base_dir, |
|
361
|
|
|
|
|
|
|
package_dir => $new_pkg_dir, |
|
362
|
|
|
|
|
|
|
installed_on => $repos->now }; |
|
363
|
|
|
|
|
|
|
foreach my $conf_field ( keys %{ $conf } ) { |
|
364
|
|
|
|
|
|
|
$info->{ $conf_field } = $conf->{ $conf_field }; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
DEBUG && _w( 1, "Trying to save package info: ", Dumper( $info ) ); |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
$repos->save_package( $info ); |
|
369
|
|
|
|
|
|
|
eval { $repos->save() }; |
|
370
|
|
|
|
|
|
|
if ( $@ ) { |
|
371
|
|
|
|
|
|
|
chdir( $base_dir ); |
|
372
|
|
|
|
|
|
|
$class->_remove_directory_tree( $full_pkg_dir ); |
|
373
|
|
|
|
|
|
|
die "Could not save data to installed package database. " . |
|
374
|
|
|
|
|
|
|
"Error returned: $@ " . |
|
375
|
|
|
|
|
|
|
"Aborting package installation."; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
DEBUG && _w( 1, "Saved repository ok." ); |
|
378
|
|
|
|
|
|
|
chdir( $old_pwd ); |
|
379
|
|
|
|
|
|
|
return $info; |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# Install a package from the base OpenInteract directory to a website |
|
384
|
|
|
|
|
|
|
# directory. This is known in 'oi_manage' terms as 'applying' a |
|
385
|
|
|
|
|
|
|
# package. Note that if you're upgrading the app calling this module |
|
386
|
|
|
|
|
|
|
# must first get rid of the old package. |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub install_to_website { |
|
389
|
|
|
|
|
|
|
my ( $class, $base_repository, $website_repository, $info, $CONFIG ) = @_; |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Be sure to have the website directory, website name, and package |
|
392
|
|
|
|
|
|
|
# directory set |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
unless ( $info->{website_name} ) { |
|
395
|
|
|
|
|
|
|
die "Website name not set in package object.\n"; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
my $package_name_version = "$info->{name}-$info->{version}"; |
|
398
|
|
|
|
|
|
|
$info->{website_dir} ||= $website_repository->{META_INF}{base_dir}; |
|
399
|
|
|
|
|
|
|
$info->{package_dir} ||= join( '/', 'pkg', $package_name_version ); |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# Then create package directory within the website directory |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
my $pkg_dir = join( '/', $info->{website_dir}, $info->{package_dir} ); |
|
404
|
|
|
|
|
|
|
if ( -d $pkg_dir ) { die "Package directory $pkg_dir already exists.\n" } |
|
405
|
|
|
|
|
|
|
mkdir( $pkg_dir, 0775 ) || die "Cannot create $pkg_dir : $!"; |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Next move to the base package directory (we return to the original |
|
408
|
|
|
|
|
|
|
# directory just before the routine exits) |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
my $pwd = cwd; |
|
411
|
|
|
|
|
|
|
chdir( "$info->{base_dir}/pkg/$package_name_version" ); |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# ...then ensure that it has all its files |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
my @missing = ExtUtils::Manifest::manicheck; |
|
416
|
|
|
|
|
|
|
if ( scalar @missing ) { |
|
417
|
|
|
|
|
|
|
die "Cannot install package $info->{name}-$info->{version} to website ", |
|
418
|
|
|
|
|
|
|
"-- the base package has files that are specified in MANIFEST missing ", |
|
419
|
|
|
|
|
|
|
"from the filesystem: @missing. Please fix the situation.\n"; |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# ...and get all the filenames from MANIFEST |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
my $BASE_FILES = ExtUtils::Manifest::maniread; |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Now create the subdirectories and copy the configs |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
$class->create_subdirectories( $pkg_dir, $info->{website_name} ); |
|
429
|
|
|
|
|
|
|
$class->_copy_spops_config_file( $info, $CONFIG, 'spops.perl' ); |
|
430
|
|
|
|
|
|
|
$class->_copy_spops_config_file( $info, $CONFIG, 'spops.perl.ldap' ); |
|
431
|
|
|
|
|
|
|
$class->_copy_action_config_file( $info, $CONFIG ); |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
# Now copy over the struct/, script/, data/, template/, html/, |
|
434
|
|
|
|
|
|
|
# html/images/ and doc/ files -- intact with no translations, as |
|
435
|
|
|
|
|
|
|
# long as they appear in the MANIFEST file (read in earlier) |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# The value of the subdir key is the root where the files will be |
|
438
|
|
|
|
|
|
|
# copied -- so files in the 'widget' directory of the package will |
|
439
|
|
|
|
|
|
|
# be copied to the 'template/' subdirectory of the website, while |
|
440
|
|
|
|
|
|
|
# the files in the 'data' directory of the package will be copied |
|
441
|
|
|
|
|
|
|
# to the 'data' directory of the *package* in the website. |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
my %subdir_match = ( |
|
444
|
|
|
|
|
|
|
struct => "$pkg_dir/struct", |
|
445
|
|
|
|
|
|
|
data => "$pkg_dir/data", |
|
446
|
|
|
|
|
|
|
template => "$pkg_dir/template", |
|
447
|
|
|
|
|
|
|
widget => "$info->{website_dir}/template", |
|
448
|
|
|
|
|
|
|
doc => "$pkg_dir/doc", |
|
449
|
|
|
|
|
|
|
script => "$pkg_dir/script", |
|
450
|
|
|
|
|
|
|
html => "$info->{website_dir}/html" ); |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
my $pkg_file_list = [ keys %{ $BASE_FILES } ]; |
|
453
|
|
|
|
|
|
|
foreach my $sub_dir ( sort keys %subdir_match ) { |
|
454
|
|
|
|
|
|
|
$class->_copy_package_files( $subdir_match{ $sub_dir }, |
|
455
|
|
|
|
|
|
|
$sub_dir, |
|
456
|
|
|
|
|
|
|
$pkg_file_list ); |
|
457
|
|
|
|
|
|
|
} |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
######################################## |
|
460
|
|
|
|
|
|
|
# TODO: For each file copied over to the /html directory, create a |
|
461
|
|
|
|
|
|
|
# 'page' object in the system for it. Note that we might have to |
|
462
|
|
|
|
|
|
|
# hook this up with the system that ensures we don't overwrite |
|
463
|
|
|
|
|
|
|
# certain files. So we might need to either remove it from the |
|
464
|
|
|
|
|
|
|
# _copy_package_files() routine, or add an argument to that |
|
465
|
|
|
|
|
|
|
# routine that lets us pass in a coderef to execute with every |
|
466
|
|
|
|
|
|
|
# item copied over. |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# ACK -- here's a problem. We don't know if we can even create an |
|
469
|
|
|
|
|
|
|
# $R yet, because (1) the base_page package might not have even |
|
470
|
|
|
|
|
|
|
# been installed yet (when creating a website) and (2) the user |
|
471
|
|
|
|
|
|
|
# hasn't yet configured the database (etc.) |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# We can get around this whenever we rewrite |
|
474
|
|
|
|
|
|
|
# Package/PackageRepository/oi_manage, but until then we will tell |
|
475
|
|
|
|
|
|
|
# people to include the relevant data inserts with packages that |
|
476
|
|
|
|
|
|
|
# include HTML documents. |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Until then, here's what this might look like :-) |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# # Now do the HTML files, but also create records for each of the |
|
481
|
|
|
|
|
|
|
# # HTML files in the 'page' table |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# my $copied = $class->_copy_package_files( "$info->{website_dir}/html", |
|
484
|
|
|
|
|
|
|
# 'html', |
|
485
|
|
|
|
|
|
|
# $pkg_file_list ); |
|
486
|
|
|
|
|
|
|
# my @html_locations = map { s/^html//; $_ } @{ $copied }; |
|
487
|
|
|
|
|
|
|
# foreach my $location ( @html_locations ) { |
|
488
|
|
|
|
|
|
|
# my $page = $R->page->fetch( $location, { skip_security => 1 } ); |
|
489
|
|
|
|
|
|
|
# next if ( $page ); |
|
490
|
|
|
|
|
|
|
# eval { |
|
491
|
|
|
|
|
|
|
# $R->page->new({ location => $location, |
|
492
|
|
|
|
|
|
|
# ... }) |
|
493
|
|
|
|
|
|
|
# ->save({ skip_security => 1 }); |
|
494
|
|
|
|
|
|
|
# }; |
|
495
|
|
|
|
|
|
|
# } |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# Now copy the MANIFEST.SKIP file and package.conf, so we can run |
|
498
|
|
|
|
|
|
|
# 'check_package' on the package directory (once complete) as well as |
|
499
|
|
|
|
|
|
|
# generate a MANIFEST once we're done copying files |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
foreach my $root_file ( 'MANIFEST.SKIP', 'package.conf' ) { |
|
502
|
|
|
|
|
|
|
cp( $root_file, "$pkg_dir/$root_file" ) |
|
503
|
|
|
|
|
|
|
|| _w( 0, "Cannot copy $root_file to $pkg_dir/$root_file : $!" ); |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
$class->_copy_handler_files( $info, $BASE_FILES ); |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
# Now go to our package directory and create a new MANIFEST file |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
chdir( $pkg_dir ); |
|
511
|
|
|
|
|
|
|
$class->_create_manifest(); |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# Finally, save this package information to the site |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
$website_repository->save_package( $info ); |
|
516
|
|
|
|
|
|
|
$website_repository->save(); |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
chdir( $pwd ); |
|
519
|
|
|
|
|
|
|
return $pkg_dir; |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
# Dump the package from the current directory (or the directory |
|
525
|
|
|
|
|
|
|
# specified in $p->{directory} into a tar.gz distribution file |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
sub export { |
|
528
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
|
529
|
|
|
|
|
|
|
$p ||= {}; |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
my $old_pwd = cwd; |
|
532
|
|
|
|
|
|
|
chdir( $p->{directory} ) if ( -d $p->{directory} ); |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
my $cwd = cwd; |
|
535
|
|
|
|
|
|
|
DEBUG && _w( 1, "Current directory exporting from: [$cwd]" ); |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
# If necessary, Read in the config and ensure that it has all the |
|
538
|
|
|
|
|
|
|
# right information |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
my $config_file = $p->{config_file} || $DEFAULT_CONF_FILE; |
|
541
|
|
|
|
|
|
|
my $config = $p->{config} || |
|
542
|
|
|
|
|
|
|
eval { $class->read_config( { file => $config_file } ) }; |
|
543
|
|
|
|
|
|
|
if ( $@ ) { |
|
544
|
|
|
|
|
|
|
die "Package configuration file cannot be opened -- \n" , |
|
545
|
|
|
|
|
|
|
"are you chdir'd to the package directory? (Reported reason \n", |
|
546
|
|
|
|
|
|
|
"for failure: $@)\n"; |
|
547
|
|
|
|
|
|
|
} |
|
548
|
|
|
|
|
|
|
DEBUG && _w( 2, "Package config read in: ", Dumper( $config ) ); |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# Check to ensure that all required fields have something in them; we |
|
551
|
|
|
|
|
|
|
# might do a 'version' check in the future, but not until it proves |
|
552
|
|
|
|
|
|
|
# necessary |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
my @missing_fields = (); |
|
555
|
|
|
|
|
|
|
foreach my $required_field ( @EXPORT_REQUIRED ) { |
|
556
|
|
|
|
|
|
|
unless ( $config->{ $required_field } ) { |
|
557
|
|
|
|
|
|
|
push @missing_fields, $required_field; |
|
558
|
|
|
|
|
|
|
} |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
if ( scalar @missing_fields ) { |
|
561
|
|
|
|
|
|
|
die "Configuration file exists [$cwd/$DEFAULT_CONF_FILE] ", |
|
562
|
|
|
|
|
|
|
"but is missing the following fields: (", |
|
563
|
|
|
|
|
|
|
join( ', ', @missing_fields ), "). Please add these fields and try again.\n"; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
DEBUG && _w( 1, "Required fields ok in package configuration file." ); |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# Now, do a check on this package's MANIFEST - are there files in |
|
568
|
|
|
|
|
|
|
# MANIFEST that don't exist? |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
warn "Package $config->{name}: checking MANIFEST for discrepancies\n"; |
|
571
|
|
|
|
|
|
|
my @missing = ExtUtils::Manifest::manicheck(); |
|
572
|
|
|
|
|
|
|
if ( scalar @missing ) { |
|
573
|
|
|
|
|
|
|
warn "\nIf the files specified do not need to be in MANIFEST any longer,\n", |
|
574
|
|
|
|
|
|
|
"please remove them from MANIFEST and re-export the package. Otherwise\n", |
|
575
|
|
|
|
|
|
|
"users installing the package will get a warning.\n"; |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
else { |
|
578
|
|
|
|
|
|
|
warn "Looks good\n\n"; |
|
579
|
|
|
|
|
|
|
} |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# Next see if there are files NOT in the MANIFEST |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
warn "Package $config->{name}: checking filesystem for files not in MANIFEST\n"; |
|
584
|
|
|
|
|
|
|
my @extra = ExtUtils::Manifest::filecheck(); |
|
585
|
|
|
|
|
|
|
if ( scalar @extra ) { |
|
586
|
|
|
|
|
|
|
warn "\nBuilding a package without these files is OK, but you can also\n", |
|
587
|
|
|
|
|
|
|
"add them as necessary to the MANIFEST and re-export the package.\n"; |
|
588
|
|
|
|
|
|
|
} |
|
589
|
|
|
|
|
|
|
else { |
|
590
|
|
|
|
|
|
|
warn "Looks good\n\n"; |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Read in the MANIFEST |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
my $package_files = ExtUtils::Manifest::maniread(); |
|
596
|
|
|
|
|
|
|
DEBUG && _w( 2, "Package info read in:\n", Dumper( $package_files ) ); |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Now, create a directory of this name-version and copy the files |
|
599
|
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
my $package_id = join( '-', $config->{name}, $config->{version} ); |
|
601
|
|
|
|
|
|
|
if ( -d $package_id ) { |
|
602
|
|
|
|
|
|
|
die "Cannot create directory [$cwd/$package_id] to ", |
|
603
|
|
|
|
|
|
|
"archive the package because it already exists.\n"; |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
mkdir( $package_id, 0777 ) |
|
606
|
|
|
|
|
|
|
|| die "Cannot create directory [$cwd/$package_id] to ", |
|
607
|
|
|
|
|
|
|
"archive the package! Error: $!"; |
|
608
|
|
|
|
|
|
|
{ |
|
609
|
|
|
|
|
|
|
local $ExtUtils::Manifest::Quiet = 1; |
|
610
|
|
|
|
|
|
|
ExtUtils::Manifest::manicopy( $package_files, "$cwd/$package_id" ); |
|
611
|
|
|
|
|
|
|
} |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# And prepend the directory name to all the files so they get |
|
614
|
|
|
|
|
|
|
# un-archived in the right way |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
my @archive_files = map { "$package_id/$_" } keys %{ $package_files }; |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
# Create the tardist |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
my $filename = "$cwd/$package_id.tar.gz"; |
|
621
|
|
|
|
|
|
|
if ( -f $filename ) { |
|
622
|
|
|
|
|
|
|
$class->_remove_directory_tree( "$cwd/$package_id" ); |
|
623
|
|
|
|
|
|
|
die "Cannot create archive [$filename] - file already exists.\n"; |
|
624
|
|
|
|
|
|
|
} |
|
625
|
|
|
|
|
|
|
my $rv = eval { $class->_create_archive( $filename, @archive_files ) }; |
|
626
|
|
|
|
|
|
|
die "Error creating archive: $@\n" if ( $@ ); |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# And remove the directory we just created |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
$class->_remove_directory_tree( "$cwd/$package_id" ); |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# Return the filename and the name/version information for the |
|
633
|
|
|
|
|
|
|
# package distribution we just created |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
chdir( $old_pwd ); |
|
636
|
|
|
|
|
|
|
if ( $rv ) { |
|
637
|
|
|
|
|
|
|
warn "\n"; |
|
638
|
|
|
|
|
|
|
return { name => $config->{name}, |
|
639
|
|
|
|
|
|
|
version => $config->{version}, |
|
640
|
|
|
|
|
|
|
file => "$filename" }; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
die "Cannot create distribution [$filename]. Error: ", Archive::Tar->error(), "\n"; |
|
643
|
|
|
|
|
|
|
} |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
# |
|
647
|
|
|
|
|
|
|
# check_package |
|
648
|
|
|
|
|
|
|
# |
|
649
|
|
|
|
|
|
|
# What we check for: |
|
650
|
|
|
|
|
|
|
# package.conf -- has name, version and author defined; all modules defined exist |
|
651
|
|
|
|
|
|
|
# conf/*.perl -- pass an 'eval' test (through SPOPS::HashFile) |
|
652
|
|
|
|
|
|
|
# OpenInteract/*.pm -- pass a 'require' test |
|
653
|
|
|
|
|
|
|
# MyApp/*.pm -- pass a 'require' test |
|
654
|
|
|
|
|
|
|
# |
|
655
|
|
|
|
|
|
|
# Parameters: |
|
656
|
|
|
|
|
|
|
# package_dir |
|
657
|
|
|
|
|
|
|
# package_name |
|
658
|
|
|
|
|
|
|
# website_name (optional) |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
sub check { |
|
661
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
|
662
|
|
|
|
|
|
|
my $status = { ok => 0 }; |
|
663
|
|
|
|
|
|
|
if ( ! $p->{package_dir} and $p->{info} ) { |
|
664
|
|
|
|
|
|
|
my $main_dir = $p->{info}{website_dir} || $p->{info}{base_dir}; |
|
665
|
|
|
|
|
|
|
$p->{package_dir} = join( '/', $main_dir, $p->{info}{package_dir} ); |
|
666
|
|
|
|
|
|
|
$p->{website_name} = $p->{info}{website_name}; |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
unless ( -d $p->{package_dir} ) { |
|
669
|
|
|
|
|
|
|
die "No valid package dir to check! (Given: $p->{package_dir})"; |
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
my $pwd = cwd; |
|
672
|
|
|
|
|
|
|
chdir( $p->{package_dir} ); |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
# First ensure the package config exists |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
unless ( -f "package.conf" ) { |
|
677
|
|
|
|
|
|
|
$status->{msg} .= "\n-- Package config (package.conf) does not " . |
|
678
|
|
|
|
|
|
|
"exist in package!\n"; |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
if ( $p->{website_name} and ! -d "$p->{website_name}/" ) { |
|
681
|
|
|
|
|
|
|
$status->{msg} .= "\n-- Website directory ($p->{website_name}/) " . |
|
682
|
|
|
|
|
|
|
"does not exist in package!\n"; |
|
683
|
|
|
|
|
|
|
} |
|
684
|
|
|
|
|
|
|
return $status if ( $status->{msg} ); |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
DEBUG && _w( 1, " - package.conf and website_name directory (if app.) ok" ); |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
# Set this after we do the initial sanity checks |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
$status->{ok}++; |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
# This is just a warning |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
if ( -f 'Changes' ) { |
|
695
|
|
|
|
|
|
|
$status->{msg} .= "\n++ File (Changes) to show package Changelog: ok" ; |
|
696
|
|
|
|
|
|
|
} |
|
697
|
|
|
|
|
|
|
else { |
|
698
|
|
|
|
|
|
|
$status->{msg} .= "\n-- File (Changes) to show package Changelog: DOES NOT EXIST\n" ; |
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
DEBUG && _w( 1, " - Changes file exists" ); |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
my $pkg_files = ExtUtils::Manifest::maniread(); |
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
# Now, first go through the config perl files |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
my @perl_files = grep /^conf.*\.perl$/, keys %{ $pkg_files }; |
|
708
|
|
|
|
|
|
|
foreach my $perl_file ( sort @perl_files ) { |
|
709
|
|
|
|
|
|
|
DEBUG && _w( 1, " checking perl file ($perl_file)" ); |
|
710
|
|
|
|
|
|
|
my $filestatus = 'ok'; |
|
711
|
|
|
|
|
|
|
my $sig = '++'; |
|
712
|
|
|
|
|
|
|
my $obj = eval { SPOPS::HashFile->new({ filename => $perl_file }) }; |
|
713
|
|
|
|
|
|
|
if ( $@ ) { |
|
714
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
715
|
|
|
|
|
|
|
$filestatus = "cannot be read in. $@\n"; |
|
716
|
|
|
|
|
|
|
$sig = '--'; |
|
717
|
|
|
|
|
|
|
} |
|
718
|
|
|
|
|
|
|
elsif ( $perl_file =~ /spops/ ) { |
|
719
|
|
|
|
|
|
|
foreach my $spops_key ( keys %{ $obj } ) { |
|
720
|
|
|
|
|
|
|
my $typeof = ref $obj->{ $spops_key } || 'not a reference'; |
|
721
|
|
|
|
|
|
|
unless ( $typeof eq 'HASH' ) { |
|
722
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
723
|
|
|
|
|
|
|
$filestatus = "invalid SPOPS configuration: value of each key must be " . |
|
724
|
|
|
|
|
|
|
"a hashref and the value [$spops_key] is [$typeof]\n"; |
|
725
|
|
|
|
|
|
|
$sig = '--'; |
|
726
|
|
|
|
|
|
|
} |
|
727
|
|
|
|
|
|
|
} |
|
728
|
|
|
|
|
|
|
} |
|
729
|
|
|
|
|
|
|
$status->{msg} .= "\n$sig File ($perl_file) $filestatus"; |
|
730
|
|
|
|
|
|
|
} |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# Next all the .pm files - stick the package directory (cwd) into |
|
733
|
|
|
|
|
|
|
# @INC so we don't have any ambiguity about where the modules |
|
734
|
|
|
|
|
|
|
# being tested come from |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
unshift @INC, cwd; |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# We suppress warnings within this block so all the interesting |
|
739
|
|
|
|
|
|
|
# stuff goes into the status |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
{ |
|
742
|
|
|
|
|
|
|
local $SIG{__WARN__} = sub { return undef }; |
|
743
|
|
|
|
|
|
|
my @pm_files = grep /\.pm$/, keys %{ $pkg_files }; |
|
744
|
|
|
|
|
|
|
foreach my $pm_file ( sort @pm_files ) { |
|
745
|
|
|
|
|
|
|
DEBUG && _w( 1, " checking module file ($pm_file)" ); |
|
746
|
|
|
|
|
|
|
my $filestatus = 'ok'; |
|
747
|
|
|
|
|
|
|
my $sig = '++'; |
|
748
|
|
|
|
|
|
|
eval { require "$pm_file" }; |
|
749
|
|
|
|
|
|
|
if ( $@ ) { |
|
750
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
751
|
|
|
|
|
|
|
$filestatus = "cannot be require'd.\n$@\n"; |
|
752
|
|
|
|
|
|
|
$sig = '--'; |
|
753
|
|
|
|
|
|
|
} |
|
754
|
|
|
|
|
|
|
$status->{msg} .= "\n$sig File ($pm_file) $filestatus"; |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
} |
|
757
|
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
# Check all the .dat files in data/ -- they should be valid perl files. |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
my @data_files = grep /^data\/.*\.dat$/, keys %{ $pkg_files }; |
|
761
|
|
|
|
|
|
|
foreach my $data_file ( sort @data_files ) { |
|
762
|
|
|
|
|
|
|
DEBUG && _w( 1, " checking data file ($data_file)" ); |
|
763
|
|
|
|
|
|
|
my $filestatus = 'ok'; |
|
764
|
|
|
|
|
|
|
my $sig = '++'; |
|
765
|
|
|
|
|
|
|
eval { $class->read_data_file( $data_file ) }; |
|
766
|
|
|
|
|
|
|
if ( $@ ) { |
|
767
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
768
|
|
|
|
|
|
|
$filestatus = "is not a valid Perl structure.\n$@\n"; |
|
769
|
|
|
|
|
|
|
$sig = '--'; |
|
770
|
|
|
|
|
|
|
} |
|
771
|
|
|
|
|
|
|
$status->{msg} .= "\n$sig File ($data_file) $filestatus"; |
|
772
|
|
|
|
|
|
|
} |
|
773
|
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# See if all the templates pass a basic syntax test -- do not log |
|
776
|
|
|
|
|
|
|
# 'plugin not found' or 'no providers for template prefix' errors, |
|
777
|
|
|
|
|
|
|
# since we assume those will be ok when it runs in the environment |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
require Template; |
|
780
|
|
|
|
|
|
|
my $template = Template->new(); |
|
781
|
|
|
|
|
|
|
my @template_files = grep ! /(\.meta|~|\.bak)$/, |
|
782
|
|
|
|
|
|
|
grep /^(template|widget)/, |
|
783
|
|
|
|
|
|
|
keys %{ $pkg_files }; |
|
784
|
|
|
|
|
|
|
my ( $out ); |
|
785
|
|
|
|
|
|
|
my @template_errors_ok = ( 'plugin not found', 'no providers for template prefix', 'file error' ); |
|
786
|
|
|
|
|
|
|
my $template_errors_re = '(' . join( '|', @template_errors_ok ) . ')'; |
|
787
|
|
|
|
|
|
|
foreach my $template_file ( sort @template_files ) { |
|
788
|
|
|
|
|
|
|
DEBUG && _w( 1, " checking template ($template_file)" ); |
|
789
|
|
|
|
|
|
|
my $filestatus = 'ok'; |
|
790
|
|
|
|
|
|
|
my $sig = '++'; |
|
791
|
|
|
|
|
|
|
eval { $template->process( $template_file, undef, \$out ) |
|
792
|
|
|
|
|
|
|
|| die $template->error(), "\n" }; |
|
793
|
|
|
|
|
|
|
if ( $@ ) { |
|
794
|
|
|
|
|
|
|
unless ( $@ =~ /$template_errors_re/ ) { |
|
795
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
796
|
|
|
|
|
|
|
$filestatus = "is not a valid Template Toolkit template.\n$@\n"; |
|
797
|
|
|
|
|
|
|
$sig = '--'; |
|
798
|
|
|
|
|
|
|
} |
|
799
|
|
|
|
|
|
|
} |
|
800
|
|
|
|
|
|
|
$status->{msg} .= "\n$sig File ($template_file) $filestatus"; |
|
801
|
|
|
|
|
|
|
} |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
# Now open up the package.conf and check to see that name, version |
|
804
|
|
|
|
|
|
|
# and author exist |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
DEBUG && _w( 1, " checking package.conf validity" ); |
|
807
|
|
|
|
|
|
|
my $config = $class->read_config({ directory => '.' }); |
|
808
|
|
|
|
|
|
|
$status->{name} = $config->{name}; |
|
809
|
|
|
|
|
|
|
my $conf_msg = ''; |
|
810
|
|
|
|
|
|
|
unless ( $config->{name} ) { |
|
811
|
|
|
|
|
|
|
$conf_msg .= "\n-- package.conf: required field 'name' is not defined."; |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
unless ( $config->{version} ) { |
|
814
|
|
|
|
|
|
|
$conf_msg .= "\n-- package.conf: required field 'version' is not defined."; |
|
815
|
|
|
|
|
|
|
} |
|
816
|
|
|
|
|
|
|
unless ( $config->{author} ) { |
|
817
|
|
|
|
|
|
|
$conf_msg .= "\n-- package.conf: required field 'author' is not defined."; |
|
818
|
|
|
|
|
|
|
} |
|
819
|
|
|
|
|
|
|
if ( ref $config->{module} eq 'ARRAY' ) { |
|
820
|
|
|
|
|
|
|
my @failed_modules = $class->_check_module_install( @{ $config->{module} } ); |
|
821
|
|
|
|
|
|
|
if ( scalar @failed_modules ) { |
|
822
|
|
|
|
|
|
|
$conf_msg .= "\n-- package.conf: the following modules are used by " . |
|
823
|
|
|
|
|
|
|
"package but not installed: " . |
|
824
|
|
|
|
|
|
|
"(" . join( ', ', @failed_modules ) . ") " . |
|
825
|
|
|
|
|
|
|
"INSTALL THESE PACKAGES BEFORE CONTINUING." |
|
826
|
|
|
|
|
|
|
} |
|
827
|
|
|
|
|
|
|
} |
|
828
|
|
|
|
|
|
|
if ( $conf_msg ) { |
|
829
|
|
|
|
|
|
|
$status->{msg} .= "$conf_msg\n"; |
|
830
|
|
|
|
|
|
|
$status->{ok} = 0; |
|
831
|
|
|
|
|
|
|
} |
|
832
|
|
|
|
|
|
|
else { |
|
833
|
|
|
|
|
|
|
$status->{msg} .= "\n++ package.conf: ok"; |
|
834
|
|
|
|
|
|
|
} |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
# While we have the package.conf open, see if there are any |
|
837
|
|
|
|
|
|
|
# modules and whether they're available |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
# Now do the check to ensure that all files in the MANIFEST exist |
|
842
|
|
|
|
|
|
|
# -- just get feedback from the manifest module, don't let it |
|
843
|
|
|
|
|
|
|
# print out results of its findings (Quiet) |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
DEBUG && _w( " checking MANIFEST against files" ); |
|
846
|
|
|
|
|
|
|
$ExtUtils::Manifest::Quiet = 1; |
|
847
|
|
|
|
|
|
|
my @missing = ExtUtils::Manifest::manicheck(); |
|
848
|
|
|
|
|
|
|
if ( scalar @missing ) { |
|
849
|
|
|
|
|
|
|
$status->{msg} .= "\n-- MANIFEST files not all in package. " . |
|
850
|
|
|
|
|
|
|
"Following not found: \n " . |
|
851
|
|
|
|
|
|
|
join( "\n ", @missing ) . "\n"; |
|
852
|
|
|
|
|
|
|
} |
|
853
|
|
|
|
|
|
|
else { |
|
854
|
|
|
|
|
|
|
$status->{msg} .= "\n++ MANIFEST files all exist in package: ok"; |
|
855
|
|
|
|
|
|
|
} |
|
856
|
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
# Now do the check to see if any extra files exist than are in the MANIFEST |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
my @extra = ExtUtils::Manifest::filecheck(); |
|
860
|
|
|
|
|
|
|
if ( scalar @extra ) { |
|
861
|
|
|
|
|
|
|
$status->{msg} .= "\n-- Files in package not in MANIFEST:\n " . |
|
862
|
|
|
|
|
|
|
join( "\n ", @extra ) . "\n"; |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
else { |
|
865
|
|
|
|
|
|
|
$status->{msg} .= "\n++ All files in package also in MANIFEST: ok"; |
|
866
|
|
|
|
|
|
|
} |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
$status->{msg} .= "\n"; |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
chdir( $pwd ); |
|
871
|
|
|
|
|
|
|
return $status; |
|
872
|
|
|
|
|
|
|
} |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
# Copy all modules from a particular package (site directory AND base |
|
875
|
|
|
|
|
|
|
# directory) to another directory |
|
876
|
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
sub copy_modules { |
|
878
|
|
|
|
|
|
|
my ( $class, $info, $to_dir ) = @_; |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
my $site_pkg_dir = join( '/', $info->{website_dir}, $info->{package_dir} ); |
|
881
|
|
|
|
|
|
|
my $site_modules = $class->_copy_module_files( $site_pkg_dir, $to_dir ); |
|
882
|
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
my $base_pkg_dir = join( '/', $info->{base_dir}, $info->{package_dir} ); |
|
884
|
|
|
|
|
|
|
my $base_modules = $class->_copy_module_files( $base_pkg_dir, $to_dir ); |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
return [ sort @{ $base_modules }, @{ $site_modules } ]; |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
sub _copy_module_files { |
|
891
|
|
|
|
|
|
|
my ( $class, $pkg_dir, $to_dir ) = @_; |
|
892
|
|
|
|
|
|
|
unless ( -d $pkg_dir ) { |
|
893
|
|
|
|
|
|
|
die "Package directory ($pkg_dir) does not exist -- cannot copy files.\n"; |
|
894
|
|
|
|
|
|
|
} |
|
895
|
|
|
|
|
|
|
unless ( -d $to_dir ) { |
|
896
|
|
|
|
|
|
|
die "Destination for package modules ($to_dir) does not exist -- cannot copy files.\n"; |
|
897
|
|
|
|
|
|
|
} |
|
898
|
|
|
|
|
|
|
my $current_dir = cwd; |
|
899
|
|
|
|
|
|
|
chdir( $pkg_dir ); |
|
900
|
|
|
|
|
|
|
$to_dir =~ s|/$||; |
|
901
|
|
|
|
|
|
|
my $pkg_files = ExtUtils::Manifest::maniread; |
|
902
|
|
|
|
|
|
|
my @module_files = grep /\.pm$/, keys %{ $pkg_files }; |
|
903
|
|
|
|
|
|
|
my @module_files_full = (); |
|
904
|
|
|
|
|
|
|
my ( %dir_ok ); |
|
905
|
|
|
|
|
|
|
foreach my $filename ( @module_files ) { |
|
906
|
|
|
|
|
|
|
my $full_dest_file = join( '/', $to_dir, $filename ); |
|
907
|
|
|
|
|
|
|
#warn "Trying to copy file ($filename) to ($full_dest_file)\n"; |
|
908
|
|
|
|
|
|
|
next if ( -f $full_dest_file ); |
|
909
|
|
|
|
|
|
|
my $full_dest_dir = File::Basename::dirname( $full_dest_file ); |
|
910
|
|
|
|
|
|
|
unless ( $dir_ok{ $full_dest_dir } ) { |
|
911
|
|
|
|
|
|
|
File::Path::mkpath( $full_dest_dir ); |
|
912
|
|
|
|
|
|
|
$dir_ok{ $full_dest_dir }++; |
|
913
|
|
|
|
|
|
|
} |
|
914
|
|
|
|
|
|
|
cp( $filename, $full_dest_file ); |
|
915
|
|
|
|
|
|
|
push @module_files_full, $full_dest_file; |
|
916
|
|
|
|
|
|
|
} |
|
917
|
|
|
|
|
|
|
chdir( $current_dir ); |
|
918
|
|
|
|
|
|
|
return \@module_files_full; |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
sub read_data_file { |
|
923
|
|
|
|
|
|
|
my ( $class, $filename ) = @_; |
|
924
|
|
|
|
|
|
|
open( D, $filename ) || die "Cannot open: $@"; |
|
925
|
|
|
|
|
|
|
local $/ = undef; |
|
926
|
|
|
|
|
|
|
my $raw = ; |
|
927
|
|
|
|
|
|
|
close( D ); |
|
928
|
|
|
|
|
|
|
my ( $dat ); |
|
929
|
|
|
|
|
|
|
{ |
|
930
|
|
|
|
|
|
|
no strict 'vars'; |
|
931
|
|
|
|
|
|
|
$dat = eval $raw; |
|
932
|
|
|
|
|
|
|
die $@ if ( $@ ); |
|
933
|
|
|
|
|
|
|
} |
|
934
|
|
|
|
|
|
|
return $dat; |
|
935
|
|
|
|
|
|
|
} |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
sub remove { |
|
938
|
|
|
|
|
|
|
my ( $class, $repository, $info, $opt ) = @_; |
|
939
|
|
|
|
|
|
|
$repository->remove_package( $info ); |
|
940
|
|
|
|
|
|
|
$repository->save(); |
|
941
|
|
|
|
|
|
|
my $base_dir = $info->{website_dir} || $info->{base_dir}; |
|
942
|
|
|
|
|
|
|
my $full_dir = join( '/', $base_dir, $info->{package_dir} ); |
|
943
|
|
|
|
|
|
|
if ( $opt eq 'directory' ) { |
|
944
|
|
|
|
|
|
|
return $class->_remove_directory_tree( $full_dir ); |
|
945
|
|
|
|
|
|
|
} |
|
946
|
|
|
|
|
|
|
return 1; |
|
947
|
|
|
|
|
|
|
} |
|
948
|
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
sub read_config { |
|
951
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
|
952
|
|
|
|
|
|
|
if ( ( $p->{info} or $p->{directory} ) and ! $p->{file} ) { |
|
953
|
|
|
|
|
|
|
my $dir = $p->{directory}; |
|
954
|
|
|
|
|
|
|
unless ( -d $dir ) { |
|
955
|
|
|
|
|
|
|
$dir = $p->{info}{website_dir} || $p->{info}{base_dir}; |
|
956
|
|
|
|
|
|
|
$dir = join( '/', $dir, $p->{info}{package_dir} ); |
|
957
|
|
|
|
|
|
|
} |
|
958
|
|
|
|
|
|
|
$p->{file} = join( '/', $dir, $DEFAULT_CONF_FILE ); |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
unless ( -f $p->{file} ) { |
|
961
|
|
|
|
|
|
|
die "Package configuration file ($p->{file}) does not exist.\n"; |
|
962
|
|
|
|
|
|
|
} |
|
963
|
|
|
|
|
|
|
open( CONF, $p->{file} ) || die "Error opening $p->{file}: $!"; |
|
964
|
|
|
|
|
|
|
my $config = {}; |
|
965
|
|
|
|
|
|
|
while ( ) { |
|
966
|
|
|
|
|
|
|
next if ( /^\s*\#/ ); |
|
967
|
|
|
|
|
|
|
next if ( /^\s*$/ ); |
|
968
|
|
|
|
|
|
|
chomp; |
|
969
|
|
|
|
|
|
|
s/\r//g; |
|
970
|
|
|
|
|
|
|
s/^\s+//; |
|
971
|
|
|
|
|
|
|
s/\s+$//; |
|
972
|
|
|
|
|
|
|
my ( $k, $v ) = split /\s+/, $_, 2; |
|
973
|
|
|
|
|
|
|
last if ( $k eq 'description' ); |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# If there are multiple values possible, make a list |
|
976
|
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
if ( $CONF_LIST_KEYS{ $k } ) { |
|
978
|
|
|
|
|
|
|
push @{ $config->{ $k } }, $v; |
|
979
|
|
|
|
|
|
|
} |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
# Otherwise, if it's a key -> key -> value set; add to list |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
elsif ( $CONF_HASH_KEYS{ $k } ) { |
|
984
|
|
|
|
|
|
|
my ( $sub_key, $sub_value ) = split /\s+/, $v, 2; |
|
985
|
|
|
|
|
|
|
$config->{ $k }{ $sub_key } = $sub_value; |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
# If not all that, then simple key -> value |
|
989
|
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
else { |
|
991
|
|
|
|
|
|
|
$config->{ $k } = $v; |
|
992
|
|
|
|
|
|
|
} |
|
993
|
|
|
|
|
|
|
} |
|
994
|
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
# Once all that is done, read the description in all at once |
|
996
|
|
|
|
|
|
|
{ |
|
997
|
|
|
|
|
|
|
local $/ = undef; |
|
998
|
|
|
|
|
|
|
$config->{description} = ; |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
chomp $config->{description}; |
|
1001
|
|
|
|
|
|
|
close( CONF ); |
|
1002
|
|
|
|
|
|
|
return $config; |
|
1003
|
|
|
|
|
|
|
} |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
# Read in a file (parameter 'from_file') and write it to a file |
|
1007
|
|
|
|
|
|
|
# (parameter 'to_file'), doing replacements on keys along the way. The |
|
1008
|
|
|
|
|
|
|
# keys are found in the list 'from_text' and the replacements are |
|
1009
|
|
|
|
|
|
|
# found in the list 'to_text'. |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
sub replace_and_copy { |
|
1012
|
|
|
|
|
|
|
my ( $class, $p ) = @_; |
|
1013
|
|
|
|
|
|
|
unless ( $p->{from_text} and $p->{to_text} |
|
1014
|
|
|
|
|
|
|
and $p->{from_file} and $p->{to_file} ) { |
|
1015
|
|
|
|
|
|
|
die "Not enough params for copy/replace! ", Dumper( $p ), "\n"; |
|
1016
|
|
|
|
|
|
|
} |
|
1017
|
|
|
|
|
|
|
cp( $p->{from_file}, "$p->{to_file}.old" ) |
|
1018
|
|
|
|
|
|
|
|| die "No copy $p->{from_file} -> $p->{to_file}.old: $!"; |
|
1019
|
|
|
|
|
|
|
open( OLD, "$p->{to_file}.old" ) |
|
1020
|
|
|
|
|
|
|
|| die "Cannot open copied file: $!"; |
|
1021
|
|
|
|
|
|
|
open( NEW, "> $p->{to_file}" ) |
|
1022
|
|
|
|
|
|
|
|| die "Cannot open new file: $!"; |
|
1023
|
|
|
|
|
|
|
while ( ) { |
|
1024
|
|
|
|
|
|
|
my $line = $_; |
|
1025
|
|
|
|
|
|
|
for ( my $i = 0; $i < scalar @{ $p->{from_text} }; $i++ ) { |
|
1026
|
|
|
|
|
|
|
$line =~ s/$p->{from_text}->[ $i ]/$p->{to_text}->[ $i ]/g; |
|
1027
|
|
|
|
|
|
|
} |
|
1028
|
|
|
|
|
|
|
print NEW $line; |
|
1029
|
|
|
|
|
|
|
} |
|
1030
|
|
|
|
|
|
|
close( NEW ); |
|
1031
|
|
|
|
|
|
|
close( OLD ); |
|
1032
|
|
|
|
|
|
|
unlink( "$p->{to_file}.old" ) |
|
1033
|
|
|
|
|
|
|
|| warn qq/Cannot erase temp file (you should do a /, |
|
1034
|
|
|
|
|
|
|
qq/'rm -f `find . -name "*.old"`' after this is done): $!\n/; |
|
1035
|
|
|
|
|
|
|
} |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
# Find a file that exists in either the website directory or the base |
|
1039
|
|
|
|
|
|
|
# installation directory. @file_list defines a number of choices |
|
1040
|
|
|
|
|
|
|
# available for the file to be named. |
|
1041
|
|
|
|
|
|
|
# |
|
1042
|
|
|
|
|
|
|
# Returns: the full path and filename of the first match |
|
1043
|
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
sub find_file { |
|
1045
|
|
|
|
|
|
|
my ( $class, $info, @file_list ) = @_; |
|
1046
|
|
|
|
|
|
|
return undef unless ( scalar @file_list ); |
|
1047
|
|
|
|
|
|
|
foreach my $base_file ( @file_list ) { |
|
1048
|
|
|
|
|
|
|
if ( $info->{website_dir} ) { |
|
1049
|
|
|
|
|
|
|
my $filename = join( '/', $info->{website_dir}, $info->{package_dir}, $base_file ); |
|
1050
|
|
|
|
|
|
|
DEBUG && _w( 1, "Created filename <<$filename>> using the website directory" ); |
|
1051
|
|
|
|
|
|
|
return $filename if ( -f $filename ); |
|
1052
|
|
|
|
|
|
|
} |
|
1053
|
|
|
|
|
|
|
my $filename = join( '/', $info->{base_dir}, $info->{package_dir}, $base_file ); |
|
1054
|
|
|
|
|
|
|
DEBUG && _w( 1, "Created filename <<$filename>> using the base installation directory" ); |
|
1055
|
|
|
|
|
|
|
return $filename if ( -f $filename ); |
|
1056
|
|
|
|
|
|
|
} |
|
1057
|
|
|
|
|
|
|
DEBUG && _w( 1, "No existing filename found matching @file_list" ); |
|
1058
|
|
|
|
|
|
|
return undef; |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
# Put the base and website package directories into @INC |
|
1063
|
|
|
|
|
|
|
# |
|
1064
|
|
|
|
|
|
|
# NOTE: THIS WILL PROBABLY BE REMOVED |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
sub add_to_inc { |
|
1067
|
|
|
|
|
|
|
my ( $class, $info ) = @_; |
|
1068
|
|
|
|
|
|
|
my @my_inc = (); |
|
1069
|
|
|
|
|
|
|
my $base_package_dir = join( '/', $info->{base_dir}, $info->{package_dir} ); |
|
1070
|
|
|
|
|
|
|
unshift @my_inc, $base_package_dir if ( -d $base_package_dir ); |
|
1071
|
|
|
|
|
|
|
if ( $info->{website_dir} ) { |
|
1072
|
|
|
|
|
|
|
my $app_package_dir = join( '/', $info->{website_dir}, $info->{package_dir} ); |
|
1073
|
|
|
|
|
|
|
unshift @my_inc, $app_package_dir if ( -d $app_package_dir ); |
|
1074
|
|
|
|
|
|
|
} |
|
1075
|
|
|
|
|
|
|
#unshift @INC, @my_inc; |
|
1076
|
|
|
|
|
|
|
return @my_inc; |
|
1077
|
|
|
|
|
|
|
} |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
sub _check_module_install { |
|
1081
|
|
|
|
|
|
|
my ( $class, @modules ) = @_; |
|
1082
|
|
|
|
|
|
|
my ( @failed_modules ); |
|
1083
|
|
|
|
|
|
|
MODULE: |
|
1084
|
|
|
|
|
|
|
foreach my $module ( @modules ) { |
|
1085
|
|
|
|
|
|
|
next unless ( $module ); |
|
1086
|
|
|
|
|
|
|
if ( $module =~ /\|\|/ ) { |
|
1087
|
|
|
|
|
|
|
my @alt_modules = split /\s*\|\|\s*/, $module; |
|
1088
|
|
|
|
|
|
|
foreach my $alt_module ( @alt_modules ) { |
|
1089
|
|
|
|
|
|
|
eval "require $alt_module"; |
|
1090
|
|
|
|
|
|
|
next MODULE unless ( $@ ); |
|
1091
|
|
|
|
|
|
|
} |
|
1092
|
|
|
|
|
|
|
push @failed_modules, join( ' or ', @alt_modules ); |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
else { |
|
1095
|
|
|
|
|
|
|
eval "require $module"; |
|
1096
|
|
|
|
|
|
|
push @failed_modules, $module if ( $@ ); |
|
1097
|
|
|
|
|
|
|
} |
|
1098
|
|
|
|
|
|
|
} |
|
1099
|
|
|
|
|
|
|
return @failed_modules; |
|
1100
|
|
|
|
|
|
|
} |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
sub _create_archive { |
|
1104
|
|
|
|
|
|
|
my ( $class, $filename, @files ) = @_; |
|
1105
|
|
|
|
|
|
|
return undef unless ( $filename and scalar @files ); |
|
1106
|
|
|
|
|
|
|
DEBUG && _w( 2, "Creating archive ($filename) with files:\n", join( ' -- ', @files ) ); |
|
1107
|
|
|
|
|
|
|
die "file exits" if ( -f $filename ); |
|
1108
|
|
|
|
|
|
|
my $rv = undef; |
|
1109
|
|
|
|
|
|
|
if ( Archive::Tar->VERSION >= 0.20 ) { |
|
1110
|
|
|
|
|
|
|
DEBUG && _w( 1, "Creating archive using NEW Archive::Tar syntax." ); |
|
1111
|
|
|
|
|
|
|
$rv = Archive::Tar->create_archive( $filename, 9, @files ); |
|
1112
|
|
|
|
|
|
|
unless ( $rv ) { $ARCHIVE_ERROR = Archive::Tar->error() } |
|
1113
|
|
|
|
|
|
|
} |
|
1114
|
|
|
|
|
|
|
else { |
|
1115
|
|
|
|
|
|
|
DEBUG && _w( 1, "Creating archive using OLD Archive::Tar syntax." ); |
|
1116
|
|
|
|
|
|
|
my $tar = Archive::Tar->new(); |
|
1117
|
|
|
|
|
|
|
$tar->add_files( @files ); |
|
1118
|
|
|
|
|
|
|
$tar->write( $filename, 1 ); |
|
1119
|
|
|
|
|
|
|
if ( $Archive::Tar::error ) { |
|
1120
|
|
|
|
|
|
|
$ARCHIVE_ERROR = "Possible errors: $Archive::Tar::error / $@ / $!"; |
|
1121
|
|
|
|
|
|
|
} |
|
1122
|
|
|
|
|
|
|
else { |
|
1123
|
|
|
|
|
|
|
$rv++; |
|
1124
|
|
|
|
|
|
|
} |
|
1125
|
|
|
|
|
|
|
} |
|
1126
|
|
|
|
|
|
|
return $rv; |
|
1127
|
|
|
|
|
|
|
} |
|
1128
|
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
# Used to accommodate earlier versions of Archive::Tar (such as those |
|
1130
|
|
|
|
|
|
|
# shipped with ActivePerl, sigh) |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
# * You should already be chdir'd to the directory where this will be |
|
1133
|
|
|
|
|
|
|
# unpacked |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
# * I'm not sure if the version reference below is correct -- I |
|
1136
|
|
|
|
|
|
|
# *think* it might be 0.20, but I'm not entirely sure. |
|
1137
|
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub _extract_archive { |
|
1139
|
|
|
|
|
|
|
my ( $class, $filename ) = @_; |
|
1140
|
|
|
|
|
|
|
return undef unless ( -f $filename ); |
|
1141
|
|
|
|
|
|
|
my $rv = undef; |
|
1142
|
|
|
|
|
|
|
if ( $Archive::Tar::VERSION >= 0.20 ) { |
|
1143
|
|
|
|
|
|
|
$rv = Archive::Tar->extract_archive( $filename ); |
|
1144
|
|
|
|
|
|
|
unless ( $rv ) { $ARCHIVE_ERROR = Archive::Tar->error() } |
|
1145
|
|
|
|
|
|
|
} |
|
1146
|
|
|
|
|
|
|
else { |
|
1147
|
|
|
|
|
|
|
my $tar = Archive::Tar->new(); |
|
1148
|
|
|
|
|
|
|
$tar->read( $filename, 1 ); |
|
1149
|
|
|
|
|
|
|
my @files = $tar->list_files(); |
|
1150
|
|
|
|
|
|
|
$tar->extract( @files ); |
|
1151
|
|
|
|
|
|
|
if ( $Archive::Tar::error ) { |
|
1152
|
|
|
|
|
|
|
$ARCHIVE_ERROR = "Possible errors: $Archive::Tar::error / $@ / $!"; |
|
1153
|
|
|
|
|
|
|
} |
|
1154
|
|
|
|
|
|
|
else { |
|
1155
|
|
|
|
|
|
|
$rv++; |
|
1156
|
|
|
|
|
|
|
} |
|
1157
|
|
|
|
|
|
|
} |
|
1158
|
|
|
|
|
|
|
return $rv; |
|
1159
|
|
|
|
|
|
|
} |
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
# Copy the spops.perl file from the base install package directory to |
|
1163
|
|
|
|
|
|
|
# the website package directory Note that we have changed this |
|
1164
|
|
|
|
|
|
|
# recently (Jan 01) to keep only certain configuration variables |
|
1165
|
|
|
|
|
|
|
# *behind* -- all others are copied over to the website |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
# Also, this works with spops.perl AND spops.perl.IMPL, where 'IMPL' |
|
1168
|
|
|
|
|
|
|
# right now is generally 'ldap' |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
sub _copy_spops_config_file { |
|
1171
|
|
|
|
|
|
|
my ( $class, $info, $CONFIG, $filename ) = @_; |
|
1172
|
|
|
|
|
|
|
my $interact_pkg_dir = join( '/', $info->{base_dir}, $info->{package_dir} ); |
|
1173
|
|
|
|
|
|
|
my $website_pkg_dir = join( '/', $info->{website_dir}, $info->{package_dir} ); |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
my $spops_conf = "conf/$filename"; |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
unless ( -f "$interact_pkg_dir/$spops_conf" ) { |
|
1178
|
|
|
|
|
|
|
return undef; |
|
1179
|
|
|
|
|
|
|
} |
|
1180
|
|
|
|
|
|
|
my $spops_base = eval { SPOPS::HashFile->new({ |
|
1181
|
|
|
|
|
|
|
filename => "$interact_pkg_dir/$spops_conf" }) }; |
|
1182
|
|
|
|
|
|
|
if ( $@ ) { |
|
1183
|
|
|
|
|
|
|
_w( 0, "Cannot eval $spops_conf in ($info->{name}-$info->{version}): $@" ); |
|
1184
|
|
|
|
|
|
|
return undef; |
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
|
|
|
|
|
|
my $new_config_file = "$website_pkg_dir/$spops_conf"; |
|
1187
|
|
|
|
|
|
|
my $spops_pkg = SPOPS::HashFile->new({ |
|
1188
|
|
|
|
|
|
|
filename => $new_config_file, |
|
1189
|
|
|
|
|
|
|
perm => 'new' }); |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
foreach my $spops_key ( keys %{ $spops_base } ) { |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
# Change the class to reflect the website name |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
if ( my $old_class = $spops_base->{ $spops_key }{class} ) { |
|
1196
|
|
|
|
|
|
|
$spops_pkg->{ $spops_key }{class} = $class->_change_class_name( $info, $old_class ); |
|
1197
|
|
|
|
|
|
|
} |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
# Both the has_a and links_to use class names as keys to link |
|
1200
|
|
|
|
|
|
|
# objects; change the class names from 'OpenInteract' to the |
|
1201
|
|
|
|
|
|
|
# website name |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
if ( my $old_has_a = $spops_base->{ $spops_key }{has_a} ) { |
|
1204
|
|
|
|
|
|
|
foreach my $old_class ( keys %{ $old_has_a } ) { |
|
1205
|
|
|
|
|
|
|
my $new_class = $class->_change_class_name( $info, $old_class ); |
|
1206
|
|
|
|
|
|
|
$spops_pkg->{ $spops_key }{has_a}{ $new_class } = $old_has_a->{ $old_class }; |
|
1207
|
|
|
|
|
|
|
} |
|
1208
|
|
|
|
|
|
|
} |
|
1209
|
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
if ( my $old_links_to = $spops_base->{ $spops_key }{links_to} ) { |
|
1211
|
|
|
|
|
|
|
foreach my $old_class ( keys %{ $old_links_to } ) { |
|
1212
|
|
|
|
|
|
|
my $new_class = $class->_change_class_name( $info, $old_class ); |
|
1213
|
|
|
|
|
|
|
$spops_pkg->{ $spops_key }{links_to}{ $new_class } = $old_links_to->{ $old_class }; |
|
1214
|
|
|
|
|
|
|
} |
|
1215
|
|
|
|
|
|
|
} |
|
1216
|
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
# Copy over all the fields verbatim except those specified in the |
|
1218
|
|
|
|
|
|
|
# global %SPOPS_CONF_KEEP. Note that it's ok we're copying |
|
1219
|
|
|
|
|
|
|
# references here since we're going to dump the information to a |
|
1220
|
|
|
|
|
|
|
# file anyway |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
foreach my $to_copy ( keys %{ $spops_base->{ $spops_key } } ) { |
|
1223
|
|
|
|
|
|
|
next if ( $SPOPS_CONF_KEEP{ $to_copy } ); |
|
1224
|
|
|
|
|
|
|
next if ( ref $spops_base->{ $spops_key }{ $to_copy } eq 'CODE' ); |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
# For the 'creation_security', we want to check to see if |
|
1227
|
|
|
|
|
|
|
# we need to modify the group IDs to match what the server |
|
1228
|
|
|
|
|
|
|
# has configured |
|
1229
|
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
if ( $to_copy eq 'creation_security' ) { |
|
1231
|
|
|
|
|
|
|
my ( %new_security ); |
|
1232
|
|
|
|
|
|
|
my $orig = $spops_base->{ $spops_key }{ $to_copy }; # alias to save typing... |
|
1233
|
|
|
|
|
|
|
foreach my $scope ( keys %{ $orig } ) { |
|
1234
|
|
|
|
|
|
|
unless ( $scope eq 'g' ) { |
|
1235
|
|
|
|
|
|
|
$new_security{ $scope } = $orig->{ $scope }; |
|
1236
|
|
|
|
|
|
|
next; |
|
1237
|
|
|
|
|
|
|
} |
|
1238
|
|
|
|
|
|
|
next unless ( ref $orig->{g} eq 'HASH' and keys %{ $orig->{g} } ); |
|
1239
|
|
|
|
|
|
|
foreach my $scope_id ( keys %{ $orig->{g} } ) { |
|
1240
|
|
|
|
|
|
|
my $new_scope = $scope_id; |
|
1241
|
|
|
|
|
|
|
if ( $scope_id == PUBLIC_GROUP_ID ) { |
|
1242
|
|
|
|
|
|
|
$new_scope = $CONFIG->{default_objects}{public_group} || PUBLIC_GROUP_ID; |
|
1243
|
|
|
|
|
|
|
} |
|
1244
|
|
|
|
|
|
|
elsif ( $scope_id == SITE_ADMIN_GROUP_ID ) { |
|
1245
|
|
|
|
|
|
|
$new_scope = $CONFIG->{default_objects}{site_admin_group} || SITE_ADMIN_GROUP_ID; |
|
1246
|
|
|
|
|
|
|
} |
|
1247
|
|
|
|
|
|
|
$new_security{g}->{ $new_scope } = $orig->{g}{ $scope_id }; |
|
1248
|
|
|
|
|
|
|
} |
|
1249
|
|
|
|
|
|
|
} |
|
1250
|
|
|
|
|
|
|
$spops_pkg->{ $spops_key }{ $to_copy } = \%new_security; |
|
1251
|
|
|
|
|
|
|
} |
|
1252
|
|
|
|
|
|
|
else { |
|
1253
|
|
|
|
|
|
|
$spops_pkg->{ $spops_key }{ $to_copy } = $spops_base->{ $spops_key }{ $to_copy }; |
|
1254
|
|
|
|
|
|
|
} |
|
1255
|
|
|
|
|
|
|
} |
|
1256
|
|
|
|
|
|
|
} |
|
1257
|
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
eval { $spops_pkg->save({ dumper_level => 1 }) }; |
|
1259
|
|
|
|
|
|
|
die "Cannot save package spops file: $@\n" if ( $@ ); |
|
1260
|
|
|
|
|
|
|
return $new_config_file; |
|
1261
|
|
|
|
|
|
|
} |
|
1262
|
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
# Copy the conf/action.perl file over from the base installation to |
|
1265
|
|
|
|
|
|
|
# the website. This is somewhat easier because there are no nested |
|
1266
|
|
|
|
|
|
|
# classes we need to modify |
|
1267
|
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
sub _copy_action_config_file { |
|
1269
|
|
|
|
|
|
|
my ( $class, $info, $CONFIG ) = @_; |
|
1270
|
|
|
|
|
|
|
my $interact_pkg_dir = join( '/', $info->{base_dir}, |
|
1271
|
|
|
|
|
|
|
$info->{package_dir} ); |
|
1272
|
|
|
|
|
|
|
my $website_pkg_dir = join( '/', $info->{website_dir}, |
|
1273
|
|
|
|
|
|
|
$info->{package_dir} ); |
|
1274
|
|
|
|
|
|
|
DEBUG && _w( 1, "Coping action info from ($interact_pkg_dir)", |
|
1275
|
|
|
|
|
|
|
"to ($website_pkg_dir)" ); |
|
1276
|
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
my $action_conf = 'conf/action.perl'; |
|
1278
|
|
|
|
|
|
|
my $base_config_file = "$interact_pkg_dir/$action_conf"; |
|
1279
|
|
|
|
|
|
|
my $action_base = eval { SPOPS::HashFile->new({ |
|
1280
|
|
|
|
|
|
|
filename => $base_config_file }) }; |
|
1281
|
|
|
|
|
|
|
if ( $@ ) { |
|
1282
|
|
|
|
|
|
|
DEBUG && _w( 1, "No action info for $info->{name}-$info->{version}", |
|
1283
|
|
|
|
|
|
|
"(generally ok: $@)" ); |
|
1284
|
|
|
|
|
|
|
return undef; |
|
1285
|
|
|
|
|
|
|
} |
|
1286
|
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
my $new_config_file = "$website_pkg_dir/$action_conf"; |
|
1288
|
|
|
|
|
|
|
my $action_pkg = eval { SPOPS::HashFile->new({ |
|
1289
|
|
|
|
|
|
|
filename => $new_config_file, |
|
1290
|
|
|
|
|
|
|
perm => 'new' }) }; |
|
1291
|
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
# Go through all of the actions and all of the keys and copy them |
|
1293
|
|
|
|
|
|
|
# over to the new file. The only modification we make is to a field |
|
1294
|
|
|
|
|
|
|
# named 'class': if it exists, we modify it to fit in the website's |
|
1295
|
|
|
|
|
|
|
# namespace. |
|
1296
|
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
foreach my $action_key ( keys %{ $action_base } ) { |
|
1298
|
|
|
|
|
|
|
foreach my $action_item_key ( keys %{ $action_base->{ $action_key } } ) { |
|
1299
|
|
|
|
|
|
|
next if ( ref $action_base->{ $action_key }{ $action_item_key } eq 'CODE' ); |
|
1300
|
|
|
|
|
|
|
my $value = $action_base->{ $action_key }{ $action_item_key }; |
|
1301
|
|
|
|
|
|
|
if ( $action_item_key eq 'class' ) { |
|
1302
|
|
|
|
|
|
|
if ( $value =~ /^OpenInteract::Handler/ ) { |
|
1303
|
|
|
|
|
|
|
$value = $class->_change_class_name( $info, $value ); |
|
1304
|
|
|
|
|
|
|
} |
|
1305
|
|
|
|
|
|
|
} |
|
1306
|
|
|
|
|
|
|
$action_pkg->{ $action_key }{ $action_item_key } = $value; |
|
1307
|
|
|
|
|
|
|
} |
|
1308
|
|
|
|
|
|
|
} |
|
1309
|
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
eval { $action_pkg->save({ dumper_level => 1 }) }; |
|
1311
|
|
|
|
|
|
|
die "Cannot save package action file: $@\n" if ( $@ ); |
|
1312
|
|
|
|
|
|
|
return $new_config_file; |
|
1313
|
|
|
|
|
|
|
} |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
# Copy files from the current (package) directory into a website's |
|
1317
|
|
|
|
|
|
|
# directory and package |
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
sub _copy_package_files { |
|
1320
|
|
|
|
|
|
|
my ( $class, $root_dir, $sub_dir, $file_list ) = @_; |
|
1321
|
|
|
|
|
|
|
my @copy_file_list = grep /^$sub_dir/, @{ $file_list }; |
|
1322
|
|
|
|
|
|
|
my %no_copy = map { $_ => 1 } $class->read_readonly_file( $root_dir ); |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
foreach my $sub_dir_file ( @copy_file_list ) { |
|
1325
|
|
|
|
|
|
|
my $just_filename = $sub_dir_file; |
|
1326
|
|
|
|
|
|
|
$just_filename =~ s|^$sub_dir/||; |
|
1327
|
|
|
|
|
|
|
my $new_name = join( '/', $root_dir, $just_filename ); |
|
1328
|
|
|
|
|
|
|
next if ( $no_copy{ $just_filename } ); |
|
1329
|
|
|
|
|
|
|
eval { $class->_create_full_path( $new_name ) }; |
|
1330
|
|
|
|
|
|
|
if ( $@ ) { die "Cannot create path to file ($new_name): $@" } |
|
1331
|
|
|
|
|
|
|
eval { cp( $sub_dir_file, "$new_name" ) || die $! }; |
|
1332
|
|
|
|
|
|
|
if ( $@ ) { |
|
1333
|
|
|
|
|
|
|
_w( 0, "Cannot copy ($sub_dir_file) to ($new_name) : $@" ); |
|
1334
|
|
|
|
|
|
|
} |
|
1335
|
|
|
|
|
|
|
else { |
|
1336
|
|
|
|
|
|
|
chmod( 0775, $new_name ); |
|
1337
|
|
|
|
|
|
|
} |
|
1338
|
|
|
|
|
|
|
} |
|
1339
|
|
|
|
|
|
|
return \@copy_file_list; |
|
1340
|
|
|
|
|
|
|
} |
|
1341
|
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
sub read_readonly_file { |
|
1344
|
|
|
|
|
|
|
my ( $class, $dir ) = @_; |
|
1345
|
|
|
|
|
|
|
my $overwrite_check_file = join( '/', $dir, READONLY_FILE ); |
|
1346
|
|
|
|
|
|
|
return () unless ( -f $overwrite_check_file ); |
|
1347
|
|
|
|
|
|
|
my ( @no_write ); |
|
1348
|
|
|
|
|
|
|
if ( open( NOWRITE, $overwrite_check_file ) ) { |
|
1349
|
|
|
|
|
|
|
while ( ) { |
|
1350
|
|
|
|
|
|
|
chomp; |
|
1351
|
|
|
|
|
|
|
next if ( /^\s*$/ ); |
|
1352
|
|
|
|
|
|
|
next if ( /^\s*\#/ ); |
|
1353
|
|
|
|
|
|
|
s/^\s+//; |
|
1354
|
|
|
|
|
|
|
s/\s+$//; |
|
1355
|
|
|
|
|
|
|
push @no_write, $_; |
|
1356
|
|
|
|
|
|
|
} |
|
1357
|
|
|
|
|
|
|
close( NOWRITE ); |
|
1358
|
|
|
|
|
|
|
} |
|
1359
|
|
|
|
|
|
|
return @no_write; |
|
1360
|
|
|
|
|
|
|
} |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
# Copy handlers from the base installation to the website directory, |
|
1364
|
|
|
|
|
|
|
# putting class names into the namespace of the website |
|
1365
|
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
sub _copy_handler_files { |
|
1367
|
|
|
|
|
|
|
my ( $class, $info, $base_files ) = @_; |
|
1368
|
|
|
|
|
|
|
my $website_pkg_dir = join( '/', $info->{website_dir}, |
|
1369
|
|
|
|
|
|
|
$info->{package_dir} ); |
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
# We're only operating on the files that begin with |
|
1372
|
|
|
|
|
|
|
# 'OpenInteract/Handler'... |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
my @handler_file_list = grep /^OpenInteract\/Handler/, |
|
1375
|
|
|
|
|
|
|
keys %{ $base_files }; |
|
1376
|
|
|
|
|
|
|
foreach my $handler_filename ( @handler_file_list ) { |
|
1377
|
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
# First create the old/new class names... |
|
1379
|
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
my $handler_class = $handler_filename; |
|
1381
|
|
|
|
|
|
|
$handler_class =~ s|/|::|g; |
|
1382
|
|
|
|
|
|
|
$handler_class =~ s/\.pm$//; |
|
1383
|
|
|
|
|
|
|
my $new_handler_class = $class->_change_class_name( $info, $handler_class ); |
|
1384
|
|
|
|
|
|
|
DEBUG && _w( 1, "Old name: $handler_class; New name: $new_handler_class" ); |
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
# ... then the new filename |
|
1387
|
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
my $new_filename = "$website_pkg_dir/$handler_filename"; |
|
1389
|
|
|
|
|
|
|
$new_filename =~ s|OpenInteract/Handler|$info->{website_name}/Handler|; |
|
1390
|
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
# Now read in the old handler and write out the new one, replacing |
|
1392
|
|
|
|
|
|
|
# the 'OpenInteract::Handler::xx' with '$WEBSITE_NAME::Handler::xx' |
|
1393
|
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
open( OLDHANDLER, $handler_filename ) |
|
1395
|
|
|
|
|
|
|
|| die "Cannot read handler ($handler_filename): $!"; |
|
1396
|
|
|
|
|
|
|
eval { $class->_create_full_path( $new_filename ) }; |
|
1397
|
|
|
|
|
|
|
if ( $@ ) { |
|
1398
|
|
|
|
|
|
|
die "Cannot create a dir tree to handler ($new_filename): $@"; |
|
1399
|
|
|
|
|
|
|
} |
|
1400
|
|
|
|
|
|
|
open( NEWHANDLER, "> $new_filename" ) |
|
1401
|
|
|
|
|
|
|
|| die "Cannot write to handler ($new_filename): $!"; |
|
1402
|
|
|
|
|
|
|
while ( ) { |
|
1403
|
|
|
|
|
|
|
s/$handler_class/$new_handler_class/g; |
|
1404
|
|
|
|
|
|
|
print NEWHANDLER; |
|
1405
|
|
|
|
|
|
|
} |
|
1406
|
|
|
|
|
|
|
close( OLDHANDLER ); |
|
1407
|
|
|
|
|
|
|
close( NEWHANDLER ); |
|
1408
|
|
|
|
|
|
|
} |
|
1409
|
|
|
|
|
|
|
return \@handler_file_list; |
|
1410
|
|
|
|
|
|
|
} |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
# auxiliary routine to create necessary directories for a file, given |
|
1414
|
|
|
|
|
|
|
# the file; die on error, otherwise return a true value |
|
1415
|
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
sub _create_full_path { |
|
1417
|
|
|
|
|
|
|
my ( $class, $filename ) = @_; |
|
1418
|
|
|
|
|
|
|
my $dirname = File::Basename::dirname( $filename ); |
|
1419
|
|
|
|
|
|
|
return 1 if ( -d $dirname ); |
|
1420
|
|
|
|
|
|
|
eval { File::Path::mkpath( $dirname, undef, 0755 ) }; |
|
1421
|
|
|
|
|
|
|
return 1 unless ( $@ ); |
|
1422
|
|
|
|
|
|
|
_w( 0, "Cannot create path ($dirname): $@" ); |
|
1423
|
|
|
|
|
|
|
die $@; |
|
1424
|
|
|
|
|
|
|
} |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
# Create a manifest file in the current directory. (Note that the |
|
1428
|
|
|
|
|
|
|
# 'Quiet' and 'Verbose' parameters won't work properly until |
|
1429
|
|
|
|
|
|
|
# ExtUtils::Manifest is patched which won't likely be until 5.6.1) |
|
1430
|
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
sub _create_manifest { |
|
1432
|
|
|
|
|
|
|
my ( $class ) = @_; |
|
1433
|
|
|
|
|
|
|
local $SIG{__WARN__} = sub { return undef }; |
|
1434
|
|
|
|
|
|
|
$ExtUtils::Manifest::Quiet = 1; |
|
1435
|
|
|
|
|
|
|
$ExtUtils::Manifest::Verbose = 0; |
|
1436
|
|
|
|
|
|
|
ExtUtils::Manifest::mkmanifest(); |
|
1437
|
|
|
|
|
|
|
} |
|
1438
|
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
# Remove a directory and all files/directories beneath it. Return the |
|
1441
|
|
|
|
|
|
|
# number of removed files. |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
sub _remove_directory_tree { |
|
1444
|
|
|
|
|
|
|
my ( $class, $dir ) = @_; |
|
1445
|
|
|
|
|
|
|
my $removed_files = File::Path::rmtree( $dir, undef, undef ); |
|
1446
|
|
|
|
|
|
|
DEBUG && _w( 1, "Removed ($removed_files) files/directories from ($dir)" ); |
|
1447
|
|
|
|
|
|
|
return $removed_files; |
|
1448
|
|
|
|
|
|
|
} |
|
1449
|
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
# Modify the first argument by replacing 'OpenInteract' with either |
|
1452
|
|
|
|
|
|
|
# the second argument or the property 'website_name' of the zeroth |
|
1453
|
|
|
|
|
|
|
# argument. |
|
1454
|
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
sub _change_class_name { |
|
1456
|
|
|
|
|
|
|
my ( $class, $info, $old_class, $new_name ) = @_; |
|
1457
|
|
|
|
|
|
|
if ( ref $info and ! $new_name ) { |
|
1458
|
|
|
|
|
|
|
$new_name = $info->{website_name}; |
|
1459
|
|
|
|
|
|
|
} |
|
1460
|
|
|
|
|
|
|
$old_class =~ s/OpenInteract/$new_name/g; |
|
1461
|
|
|
|
|
|
|
return $old_class; |
|
1462
|
|
|
|
|
|
|
} |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
sub _w { |
|
1467
|
|
|
|
|
|
|
my $lev = shift; |
|
1468
|
|
|
|
|
|
|
return unless ( DEBUG >= $lev ); |
|
1469
|
|
|
|
|
|
|
my ( $pkg, $file, $line ) = caller; |
|
1470
|
|
|
|
|
|
|
my @ci = caller(1); |
|
1471
|
|
|
|
|
|
|
warn "$ci[3] ($line) >> ", join( ' ', @_ ), "\n"; |
|
1472
|
|
|
|
|
|
|
} |
|
1473
|
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
1; |
|
1475
|
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
__END__ |