line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package NCustom; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
2
|
|
2
|
use 5.008; |
|
1
|
|
|
|
|
299
|
|
|
2
|
|
|
|
|
2647
|
|
4
|
2
|
|
|
2
|
|
6
|
use strict qw(vars); |
|
2
|
|
|
|
|
72
|
|
|
2
|
|
|
|
|
8
|
|
5
|
2
|
|
|
2
|
|
4
|
use warnings; |
|
2
|
|
|
|
|
62
|
|
|
2
|
|
|
|
|
9
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
3
|
use vars qw(%Config $Transaction $req); |
|
2
|
|
|
|
|
583
|
|
|
2
|
|
|
|
|
9
|
|
8
|
2
|
|
|
2
|
|
4
|
use Carp; |
|
2
|
|
|
|
|
109
|
|
|
2
|
|
|
|
|
14
|
|
9
|
2
|
|
|
2
|
|
4
|
use File::Basename; |
|
2
|
|
|
|
|
123
|
|
|
2
|
|
|
|
|
10
|
|
10
|
2
|
|
|
2
|
|
3
|
use File::Compare; |
|
2
|
|
|
|
|
132
|
|
|
2
|
|
|
|
|
900
|
|
11
|
2
|
|
|
2
|
|
1074
|
use File::Copy; |
|
2
|
|
|
|
|
86
|
|
|
2
|
|
|
|
|
11
|
|
12
|
2
|
|
|
2
|
|
4
|
use File::Find; |
|
2
|
|
|
|
|
89
|
|
|
2
|
|
|
|
|
10
|
|
13
|
2
|
|
|
2
|
|
4
|
use File::Path; |
|
2
|
|
|
|
|
78
|
|
|
2
|
|
|
|
|
10
|
|
14
|
2
|
|
|
2
|
|
4
|
use File::Spec; |
|
2
|
|
|
|
|
74
|
|
|
2
|
|
|
|
|
22
|
|
15
|
2
|
|
|
2
|
|
3
|
use File::Temp qw(tempfile tempdir); |
|
2
|
|
|
|
|
43
|
|
|
2
|
|
|
|
|
2302
|
|
16
|
2
|
|
|
2
|
|
42962
|
use FindBin qw($Bin); #this finds the dir of the src of $0 |
|
2
|
|
|
|
|
181
|
|
|
2
|
|
|
|
|
1693
|
|
17
|
2
|
|
|
2
|
|
2366
|
use Text::ParseWords; |
|
2
|
|
|
|
|
254
|
|
|
2
|
|
|
|
|
1726
|
|
18
|
2
|
|
|
2
|
|
2964
|
use Socket; |
|
2
|
|
|
|
|
133
|
|
|
2
|
|
|
|
|
2138
|
|
19
|
2
|
|
|
2
|
|
9482
|
use Symbol qw(delete_package); |
|
2
|
|
|
|
|
1635
|
|
|
2
|
|
|
|
|
22
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
require Exporter; |
22
|
2
|
|
|
2
|
|
5
|
use AutoLoader qw(AUTOLOAD); |
|
2
|
|
|
|
|
127
|
|
|
2
|
|
|
|
|
1802
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
25
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
26
|
|
|
|
|
|
|
'all' => [ qw( &transaction &save_files &initialise &overwrite_file &append_file &prepend_file &edit_file &undo_files &required_packages $req &apt_fix &ncustom &blat_myconfig &config_edit) ] |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
29
|
|
|
|
|
|
|
our @EXPORT = qw( ); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# /////////////////////////////////////////////////////////////////// |
35
|
1
|
|
|
|
|
30
|
#<< PP: POD Prefix <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
36
|
|
|
|
|
|
|
# \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 NAME |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
NCustom - Perl extension for customising system configurations. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 SYNOPSIS |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
NCUSTOM_SCRIPT |
45
|
|
|
|
|
|
|
use NCustom; |
46
|
|
|
|
|
|
|
# do stuff in your script using NCustom routines |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
KICKSTART POST SECTION |
49
|
|
|
|
|
|
|
# install package management tool that is used in NCUSTOM_SCRIPT |
50
|
|
|
|
|
|
|
rpm -i http://install/install/rpm/apt-0.5.5cnc6-fr1.i386.rpm ; |
51
|
|
|
|
|
|
|
echo 'rpm http://install/ install/rh90_apt os extras' > /etc/apt/sources.list; |
52
|
|
|
|
|
|
|
apt-get update ; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# install and use NCustom |
55
|
|
|
|
|
|
|
apt-get -q -y install perl-NCustom ; |
56
|
|
|
|
|
|
|
ncustom -i ; |
57
|
|
|
|
|
|
|
ncustom -c src_fqdn=install.example.com ; |
58
|
|
|
|
|
|
|
ncustom -n NCUSTOM_SCRIPT |
59
|
|
|
|
|
|
|
ncustom -n smb_ldap_pdc-0.4-rh90.ncus ; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 ABSTRACT |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
NCustom provides some file editting routines and some package management hooks to assit in system configuration. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
File editting: |
66
|
|
|
|
|
|
|
The file editing routines include features such as transactions, and undo by transaction. The original files are archived within a directory tree structure. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Package management: |
69
|
|
|
|
|
|
|
You may specify packages (and minumum/maximum/exact versions) that you require to be installed, and a routine to be called if they are not installed. Your routine may use simple "rpm" commands (or whatever you want), or you may use the provided routine that uses "apt". In-built support for other package management tools is on the todo list. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
System configuration: |
72
|
|
|
|
|
|
|
A commandline interface provides for initialisation, configuration, and invocation (including invocation across the network). This enables NCustom to be used from the post section of Kickstart script. It may also be used stand alone on an already built system. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
If system configuration tweaking is minor, then scripts (even in the post section of a kickstart configuration) may be more useful. If the system configuration tweaking is related to only one rpm, then re-rolling the rpm with a new post section may be more useful. If there are several packages that need inter-related configuration (eg building a Samba, PDC, LDAP server), then NCustom may improve the speed of development of automated system configuration. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 DESCRIPTION |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
File editting: |
79
|
|
|
|
|
|
|
Files are saved into a directory structure within the users home directory. This location may be configured. A file will be saved within a directory structure named after the current transaction name, and also under the "all" directory. Because of this "all" changes, or only changes relating to a "transaciton" may be reversed. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Package management: |
82
|
|
|
|
|
|
|
When a package requirement is not met, a routine that you may provide shall be called. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
System configuration: |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 EXPORT |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
None by default. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head2 API |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=over |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=cut |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# /////////////////////////////////////////////////////////////////// |
99
|
|
|
|
|
|
|
#<< FF: Functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
100
|
|
|
|
|
|
|
# \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#==================================================================== |
103
|
|
|
|
|
|
|
# Inline testing setup and general tests |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=begin testing |
106
|
|
|
|
|
|
|
|
107
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
157
|
|
|
1
|
|
|
|
|
22474
|
|
108
|
1
|
|
|
1
|
|
2
|
use File::Compare ; |
|
1
|
|
|
|
|
106
|
|
|
1
|
|
|
|
|
875
|
|
109
|
1
|
|
|
1
|
|
1099
|
use File::Copy ; |
|
1
|
|
|
|
|
46
|
|
|
1
|
|
|
|
|
743
|
|
110
|
1
|
|
|
1
|
|
5103
|
use File::Path ; |
|
1
|
|
|
|
|
69
|
|
|
1
|
|
|
|
|
6
|
|
111
|
1
|
|
|
1
|
|
3
|
use File::Spec ; |
|
1
|
|
|
|
|
52
|
|
|
1
|
|
|
|
|
4
|
|
112
|
1
|
|
|
1
|
|
3
|
use vars qw($output $input); |
|
1
|
|
|
|
|
21
|
|
|
1
|
|
|
|
|
4
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# test setup |
115
|
0
|
|
|
|
|
0
|
$output = File::Spec->rel2abs("./t/embedded-NCustom.o"); |
116
|
0
|
|
|
|
|
0
|
$input = File::Spec->rel2abs("./t/embedded-NCustom.i"); |
117
|
1
|
50
|
|
|
|
42
|
ok( -d $input) |
118
|
|
|
|
|
|
|
|| diag("TEST: requires the data input directory be present"); |
119
|
1
|
50
|
|
|
|
15
|
-d $input || die; # as if we have that wrong we could clobber allsorts |
120
|
1
|
|
|
|
|
29
|
rmtree $output; |
121
|
1
|
|
|
|
|
371
|
mkpath $output; |
122
|
1
|
|
|
|
|
4818
|
$ENV{HOME} = $output ; # lets be non-intrusive |
123
|
|
|
|
|
|
|
|
124
|
1
|
50
|
|
1
|
|
190
|
use_ok( "NCustom", qw(:all) ) |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
9983
|
|
|
1
|
|
|
|
|
1505
|
|
|
1
|
|
|
|
|
3
|
|
125
|
|
|
|
|
|
|
|| diag("TEST: is a package"); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub test_reset { |
128
|
|
|
|
|
|
|
#Test::Inline doesnt execute test blocks in order |
129
|
|
|
|
|
|
|
#it does all basic tests first (seemingly in declaration order), |
130
|
|
|
|
|
|
|
#then examples tests (seemingly in declaration order). |
131
|
|
|
|
|
|
|
#hmmm.. test_rest can erase "why test failed" data |
132
|
2
|
|
|
16
|
|
3
|
rmtree $output; |
133
|
2
|
|
|
|
|
6893
|
mkpath $output; |
134
|
16
|
|
|
|
|
199199
|
&NCustom::constructor(); |
135
|
16
|
|
|
|
|
4447
|
transaction("tx1"); |
136
|
16
|
|
|
|
|
206
|
system("cp -r $input/subject/* $output"); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
sub output { |
140
|
16
|
50
|
|
19
|
|
62
|
$_STDOUT_ && diag($_STDOUT_); |
141
|
16
|
100
|
|
|
|
487280
|
$_STDERR_ && diag($_STDERR_); |
142
|
|
|
|
|
|
|
} |
143
|
1
|
|
|
|
|
6
|
output(); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=end testing |
146
|
1
|
|
|
|
|
7
|
|
147
|
1
|
|
|
|
|
395
|
=cut |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
#==================================================================== |
150
|
|
|
|
|
|
|
# load_config |
151
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
152
|
1
|
|
|
|
|
1
|
=begin testing |
153
|
|
|
|
|
|
|
|
154
|
1
|
|
|
|
|
2
|
NCustom::load_config(); |
155
|
1
|
50
|
|
|
|
3
|
is($NCustom::Config{'test_data1'}, "global_value") |
156
|
|
|
|
|
|
|
|| diag("TEST: sets variables from global conf file 1/3"); |
157
|
1
|
50
|
|
|
|
4
|
is($NCustom::Config{'test_data2'}, "global_value") |
158
|
|
|
|
|
|
|
|| diag("TEST: sets variables from global conf file 2/3"); |
159
|
1
|
50
|
|
|
|
14
|
is($NCustom::Config{'save_dir'}, "$output/.ncustom/save",) |
160
|
|
|
|
|
|
|
|| diag("TEST: sets variables from global conf file 3/3"); |
161
|
|
|
|
|
|
|
|
162
|
1
|
|
|
|
|
264
|
mkpath "$output/.ncustom/NCustom" ; |
163
|
1
|
|
|
|
|
266
|
copy("$input/MyConfig.pm", "$output/.ncustom/NCustom"); |
164
|
1
|
|
|
|
|
420
|
NCustom::load_config(); |
165
|
1
|
50
|
|
|
|
10
|
is($NCustom::Config{'test_data1'}, "global_value") |
166
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
167
|
|
|
|
|
|
|
TEST: |
168
|
|
|
|
|
|
|
TEST: - will use a local conf file if present |
169
|
|
|
|
|
|
|
TEST: - will still inheirit settings from global conf file |
170
|
|
|
|
|
|
|
EOF |
171
|
1
|
50
|
|
|
|
536
|
is($NCustom::Config{'test_data2'}, "local_value") |
172
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
173
|
|
|
|
|
|
|
TEST: |
174
|
|
|
|
|
|
|
TEST: - local conf file settings will override global conf file settings |
175
|
|
|
|
|
|
|
EOF |
176
|
|
|
|
|
|
|
|
177
|
1
|
|
|
|
|
5
|
my $subref = $NCustom::Config{'get_url'}; |
178
|
1
|
|
|
|
|
293
|
my $target_url = "dummy_url"; |
179
|
1
|
|
|
|
|
278
|
my $target_dir = "dummy_dir"; |
180
|
1
|
|
|
|
|
2
|
&$subref($target_url, $target_dir); |
181
|
1
|
|
|
|
|
40
|
open(STUBSLOG, "< $output/stubs.log"); |
182
|
1
|
|
|
|
|
5
|
my @lines = ; |
183
|
1
|
|
|
|
|
225
|
close(STUBSLOG); |
184
|
1
|
50
|
|
|
|
21
|
ok( grep( /get_url ${target_url} ${target_dir}/, @lines) > 0 ) |
185
|
|
|
|
|
|
|
|| diag("TEST: override works for get_url handler"); |
186
|
|
|
|
|
|
|
|
187
|
1
|
|
|
|
|
30
|
TODO: { |
188
|
1
|
|
|
|
|
11
|
local $TODO = "Unload and reload modules, eg Symbol::delete_package."; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
#testing can reset / toggle |
191
|
|
|
|
|
|
|
#Q: is this useful outside of testing context ? |
192
|
|
|
|
|
|
|
#A: no |
193
|
|
|
|
|
|
|
|
194
|
1
|
|
|
|
|
292
|
rmtree "$output/.ncustom/NCustom" ; |
195
|
1
|
|
|
|
|
3
|
NCustom::load_config(); |
196
|
1
|
50
|
|
|
|
570
|
is($NCustom::Config{'test_data1'}, "global_value") |
197
|
|
|
|
|
|
|
|| diag("TEST: is re-runnable and resets configuration 1/2"); |
198
|
1
|
50
|
|
|
|
5
|
is($NCustom::Config{'test_data2'}, "global_value") |
199
|
|
|
|
|
|
|
|| diag("TEST: is re-runnable and resets configuration 2/2"); |
200
|
|
|
|
|
|
|
} |
201
|
1
|
|
|
|
|
5
|
output(); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=end testing |
204
|
1
|
|
|
|
|
276
|
|
205
|
1
|
|
|
|
|
678
|
=cut |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
#==================================================================== |
208
|
|
|
|
|
|
|
sub load_config{ |
209
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
210
|
1
|
|
|
21
|
0
|
3
|
delete_package("NCustom::Config");# if exists $NCustom::{'Config::'}; |
|
19
|
|
|
|
|
159
|
|
211
|
19
|
|
|
|
|
114
|
delete_package("NCustom::MyConfig");# if exists $NCustom::{'MyConfig::'}; |
212
|
|
|
|
|
|
|
|
213
|
21
|
|
|
|
|
391
|
require NCustom::Config ; |
214
|
21
|
|
|
|
|
1025
|
unshift @INC, "$ENV{HOME}/.ncustom"; |
215
|
21
|
|
|
|
|
3642
|
eval {require NCustom::MyConfig;} ; |
|
21
|
|
|
|
|
275
|
|
216
|
21
|
|
|
|
|
58
|
shift @INC; |
217
|
21
|
|
|
|
|
2149
|
return 1; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
#==================================================================== |
221
|
|
|
|
|
|
|
# transaction |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item C |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
trasaction("tx1"); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Set the current trasaction. If not set it defaults to basename($0). Using the default is normally good enough. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=cut |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
#==================================================================== |
232
|
|
|
|
|
|
|
sub transaction{ |
233
|
21
|
|
|
45
|
1
|
135
|
my ($tx, @rest) = @_; |
234
|
21
|
|
33
|
|
|
128
|
$Transaction = ($tx || basename($0)); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
#==================================================================== |
238
|
|
|
|
|
|
|
# apply_config |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=begin testing |
241
|
|
|
|
|
|
|
|
242
|
1
|
|
|
|
|
2
|
test_reset(); |
243
|
|
|
|
|
|
|
|
244
|
1
|
|
|
|
|
2
|
&NCustom::apply_config(); |
245
|
|
|
|
|
|
|
|
246
|
1
|
50
|
|
|
|
4
|
ok( -d "$output/.ncustom/save/all") |
247
|
|
|
|
|
|
|
|| diag("TEST: uses a save directory"); |
248
|
1
|
50
|
|
|
|
52
|
ok( -d "$output/.ncustom/tmp") |
249
|
|
|
|
|
|
|
|| diag("TEST: uses a tmp directory"); |
250
|
1
|
50
|
|
|
|
52
|
-d "$output/.ncustom/save/all" || die; # as we could be way off course |
251
|
1
|
|
|
|
|
741
|
output(); |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=end testing |
254
|
1
|
|
|
|
|
344
|
|
255
|
1
|
|
|
|
|
13
|
=cut |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
#==================================================================== |
258
|
|
|
|
|
|
|
sub apply_config{ |
259
|
1
|
100
|
|
19
|
0
|
2
|
if(! -d $Config{'save_dir'}){ |
|
1
|
|
|
|
|
6
|
|
|
45
|
|
|
|
|
173
|
|
260
|
1
|
|
|
|
|
7
|
mkpath "$Config{'save_dir'}/all"; |
|
45
|
|
|
|
|
372
|
|
261
|
19
|
|
|
|
|
644
|
mkpath "$Config{'save_dir'}/all.new"; |
262
|
|
|
|
|
|
|
} |
263
|
18
|
100
|
|
|
|
8587
|
-d $Config{'tmp_dir'} || mkpath $Config{'tmp_dir'}; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
#TODO# error checking |
266
|
|
|
|
|
|
|
#Q: whether should test src_fqdn (dns lookup/http get/ping) ? |
267
|
|
|
|
|
|
|
#A: no, as might'nt ever matter that it is (potentially) incorrect/offline |
268
|
|
|
|
|
|
|
|
269
|
18
|
|
|
|
|
3646
|
transaction(basename($0)); #so easy to override in testing |
270
|
19
|
|
|
|
|
3272
|
return 1; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
#==================================================================== |
274
|
|
|
|
|
|
|
# crud_gaurantee |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=begin testing |
277
|
|
|
|
|
|
|
|
278
|
1
|
|
|
|
|
2
|
test_reset(); |
279
|
1
|
|
|
|
|
3
|
my $msg; |
280
|
1
|
50
|
|
|
|
7
|
ok( &NCustom::crud_gaurantee("$output/dir1/file1","read",\$msg) ) |
281
|
|
|
|
|
|
|
|| diag("TEST: says if you can read a file."); |
282
|
1
|
50
|
|
|
|
36
|
ok( &NCustom::crud_gaurantee("$output/dir1/file1","update",\$msg) ) |
283
|
|
|
|
|
|
|
|| diag("TEST: says if you can update a file."); |
284
|
1
|
50
|
|
|
|
58
|
ok(!&NCustom::crud_gaurantee("$output/dir1/file9","update",\$msg) ) |
285
|
|
|
|
|
|
|
|| diag("TEST: says if you cant update a file."); |
286
|
|
|
|
|
|
|
# should do more cant't testing |
287
|
|
|
|
|
|
|
# and test that get $msg |
288
|
|
|
|
|
|
|
# |
289
|
1
|
50
|
|
|
|
896
|
ok( &NCustom::crud_gaurantee("$output/dir1/file1","delete",\$msg) ) |
290
|
|
|
|
|
|
|
|| diag("TEST: says if you can delete a file."); |
291
|
1
|
50
|
|
|
|
331
|
ok( &NCustom::crud_gaurantee("$output/dir1/file9","create",\$msg) ) |
292
|
|
|
|
|
|
|
|| diag("TEST: says if you can create a file."); |
293
|
1
|
50
|
|
|
|
262
|
ok( &NCustom::crud_gaurantee("$output/dir1/subdir1/file9","create",\$msg) ) |
294
|
|
|
|
|
|
|
|| diag("TEST: says if you can create a file and its dirs."); |
295
|
|
|
|
|
|
|
# |
296
|
1
|
50
|
|
|
|
327
|
ok( &NCustom::crud_gaurantee("$output/dir1/file1","r",\$msg) ) |
297
|
|
|
|
|
|
|
|| diag("TEST: says if you can r a file (short notation)."); |
298
|
1
|
50
|
|
|
|
357
|
ok(!&NCustom::crud_gaurantee("$output/dir1/file9","r",\$msg) ) |
299
|
|
|
|
|
|
|
|| diag("TEST: says if you cant r a file (short notation)."); |
300
|
1
|
50
|
|
|
|
349
|
ok( &NCustom::crud_gaurantee("$output/dir1/file1","ru",\$msg) ) |
301
|
|
|
|
|
|
|
|| diag("TEST: says if you can ru a file (short notation)."); |
302
|
|
|
|
|
|
|
# should do other crud combos |
303
|
|
|
|
|
|
|
# |
304
|
1
|
|
|
|
|
339
|
output(); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=end testing |
307
|
1
|
|
|
|
|
279
|
|
308
|
1
|
|
|
|
|
317
|
=cut |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
#==================================================================== |
311
|
|
|
|
|
|
|
sub crud_gaurantee{ |
312
|
1
|
|
|
142
|
0
|
3
|
my ($file, $check, $msgref) = @_ ; |
|
1
|
|
|
|
|
7
|
|
|
19
|
|
|
|
|
1021
|
|
313
|
1
|
|
|
|
|
8
|
my $rc = 1; |
|
19
|
|
|
|
|
241
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
#TODO# fix so dont fall through to success on invalid checks |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
#CRUD: Create guarantee |
318
|
|
|
|
|
|
|
# interpreting as create/clobber |
319
|
142
|
100
|
66
|
|
|
1679
|
if($check =~ /create/i || ($check =~ /^[crud]+$/i && $check =~ /c/i )){ |
|
|
|
66
|
|
|
|
|
320
|
142
|
100
|
|
|
|
466
|
if(! -e dirname($file)){ |
321
|
142
|
|
|
|
|
2210
|
$rc = mkpath(dirname($file)); |
322
|
109
|
50
|
|
|
|
18733
|
unless($rc){$$msgref = "Cant create dir for file: $file."; return 0; } |
|
52
|
|
|
|
|
439057
|
|
|
52
|
|
|
|
|
527
|
|
323
|
|
|
|
|
|
|
} |
324
|
0
|
50
|
|
|
|
0
|
if(! -w dirname($file)){ |
325
|
0
|
|
|
|
|
0
|
$$msgref = "Cant create in dir for file: $file."; return 0; |
|
109
|
|
|
|
|
19307
|
|
326
|
|
|
|
|
|
|
} |
327
|
0
|
50
|
66
|
|
|
0
|
if(-e $file && ! -f $file){ |
328
|
0
|
|
|
|
|
0
|
$$msgref = "Shant clobber existing non-plain-file: $file."; return 0; |
|
109
|
|
|
|
|
4546
|
|
329
|
|
|
|
|
|
|
} |
330
|
0
|
50
|
66
|
|
|
0
|
if(-f $file && ! -w $file){ |
331
|
0
|
|
|
|
|
0
|
$$msgref = "Cant clobber existing plain-file: $file."; return 0; |
|
109
|
|
|
|
|
5029
|
|
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
#CRUD: Read guarantee |
336
|
0
|
100
|
66
|
|
|
0
|
if($check =~ /read/i || ($check =~ /^[crud]+$/i && $check =~ /r/i )){ |
|
|
|
66
|
|
|
|
|
337
|
0
|
100
|
|
|
|
0
|
if(! -e $file){ |
338
|
142
|
|
|
|
|
2224
|
$$msgref = "Cant read non-existant file: $file."; return 0; |
|
30
|
|
|
|
|
7749
|
|
339
|
|
|
|
|
|
|
} |
340
|
1
|
50
|
|
|
|
8
|
if(! -f $file){ |
341
|
1
|
|
|
|
|
6
|
$$msgref = "Shant read from non-plain-file: $file."; return 0; |
|
29
|
|
|
|
|
807
|
|
342
|
|
|
|
|
|
|
} |
343
|
0
|
50
|
|
|
|
0
|
if(! -r $file){ |
344
|
0
|
|
|
|
|
0
|
$$msgref = "Cant read file: $file."; return 0; |
|
29
|
|
|
|
|
1010
|
|
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
#CRUD: Update guarantee |
349
|
0
|
100
|
100
|
|
|
0
|
if($check =~ /update/i || ($check =~ /^[crud]+$/i && $check =~ /u/i )){ |
|
|
|
66
|
|
|
|
|
350
|
0
|
100
|
|
|
|
0
|
if(! -e $file){ |
351
|
141
|
|
|
|
|
1520
|
$$msgref = "Cant update non-existant file: $file."; return 0; |
|
3
|
|
|
|
|
103
|
|
352
|
|
|
|
|
|
|
} |
353
|
1
|
50
|
|
|
|
9
|
if(! -f $file){ |
354
|
1
|
|
|
|
|
5
|
$$msgref = "Shant update non-plain-file: $file."; return 0; |
|
2
|
|
|
|
|
51
|
|
355
|
|
|
|
|
|
|
} |
356
|
0
|
50
|
|
|
|
0
|
if(! -r $file){ |
357
|
0
|
|
|
|
|
0
|
$$msgref = "Cant read file: $file."; return 0; |
|
2
|
|
|
|
|
54
|
|
358
|
|
|
|
|
|
|
} |
359
|
0
|
50
|
|
|
|
0
|
if(! -w $file){ |
360
|
0
|
|
|
|
|
0
|
$$msgref = "Cant write file: $file."; return 0; |
|
2
|
|
|
|
|
100
|
|
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
#CRUD: Delete guarantee |
365
|
0
|
100
|
66
|
|
|
0
|
if($check =~ /delete/i || ($check =~ /^[crud]+$/i && $check =~ /d/i )){ |
|
|
|
66
|
|
|
|
|
366
|
|
|
|
|
|
|
#TODO# implement when we need it |
367
|
0
|
50
|
|
|
|
0
|
if(! -e $file){ |
368
|
140
|
|
|
|
|
2045
|
$$msgref = "Cant delete non-existant file: $file."; return 0; |
|
21
|
|
|
|
|
599
|
|
369
|
|
|
|
|
|
|
} |
370
|
0
|
50
|
|
|
|
0
|
if(! -f $file){ |
371
|
0
|
|
|
|
|
0
|
$$msgref = "Shant delete non-plain-file: $file."; return 0; |
|
21
|
|
|
|
|
1080
|
|
372
|
|
|
|
|
|
|
} |
373
|
0
|
50
|
|
|
|
0
|
if(! -w dirname($file)){ |
374
|
0
|
|
|
|
|
0
|
$$msgref = "Cant delete from dir of file: $file."; return 0; |
|
21
|
|
|
|
|
3241
|
|
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
0
|
|
|
|
|
0
|
return 1; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
#==================================================================== |
382
|
|
|
|
|
|
|
# save_files, save_file, save_file2 |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=item C |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=begin example |
387
|
|
|
|
|
|
|
|
388
|
1
|
|
|
|
|
3
|
test_reset(); |
389
|
1
|
50
|
|
|
|
2
|
ok(-f "$output/dir2/file1") |
390
|
|
|
|
|
|
|
|| diag("TEST: must copy over the subject dir"); |
391
|
1
|
50
|
|
|
|
5
|
can_ok("NCustom", qw(save_files)) |
392
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=end example |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=for example begin |
397
|
|
|
|
|
|
|
|
398
|
1
|
|
|
|
|
251
|
save_files("~/dir2/file1"); |
399
|
|
|
|
|
|
|
|
400
|
1
|
|
|
|
|
1539
|
save_files(<<' EOF'); |
401
|
|
|
|
|
|
|
~/dir2/file2 |
402
|
|
|
|
|
|
|
~/dir3/* |
403
|
|
|
|
|
|
|
EOF |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=for example end |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
There is not much point to this - the customise works or not. |
408
|
|
|
|
|
|
|
But it helps while developing the customisation. |
409
|
|
|
|
|
|
|
Note: changes effected by using NCustom functions are saved automatically. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=for example_testing |
412
|
1
|
50
|
|
|
|
960
|
ok(-f "$output/.ncustom/save/all/$output/dir2/file1") |
413
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
414
|
|
|
|
|
|
|
TEST: |
415
|
|
|
|
|
|
|
TEST: - saves given file(s) to the overall archive |
416
|
|
|
|
|
|
|
TEST: - performs filename expansion eg ~/ |
417
|
|
|
|
|
|
|
EOF |
418
|
1
|
50
|
|
|
|
14
|
ok(-f "$output/.ncustom/save/tx1/$output/dir2/file1") |
419
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
420
|
|
|
|
|
|
|
TEST: |
421
|
|
|
|
|
|
|
TEST: - also saves given file(s) to the current tx archive |
422
|
|
|
|
|
|
|
EOF |
423
|
1
|
50
|
|
|
|
60
|
ok(-f "$output/.ncustom/save/all/$output/dir2/file2") |
424
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
425
|
|
|
|
|
|
|
TEST: multiple arguments: |
426
|
|
|
|
|
|
|
TEST: - accepts multiple arguments in one newline delimited string |
427
|
|
|
|
|
|
|
TEST: - are also saved to both the overall, and current tx, archives 1/2 |
428
|
|
|
|
|
|
|
EOF |
429
|
1
|
50
|
|
|
|
10778
|
ok(-f "$output/.ncustom/save/tx1/$output/dir2/file2") |
430
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
431
|
|
|
|
|
|
|
TEST: multiple arguments: |
432
|
|
|
|
|
|
|
TEST: - are also saved to both the overall, and current tx, archives 2/2 |
433
|
|
|
|
|
|
|
EOF |
434
|
1
|
50
|
|
|
|
457
|
ok(-f "$output/.ncustom/save/all/$output/dir3/file1") |
435
|
|
|
|
|
|
|
|| diag("TEST: supports wildcarding 1/4"); |
436
|
1
|
50
|
|
|
|
352
|
ok(-f "$output/.ncustom/save/tx1/$output/dir3/file1") |
437
|
|
|
|
|
|
|
|| diag("TEST: supports wildcarding 2/4"); |
438
|
1
|
50
|
|
|
|
313
|
ok(-f "$output/.ncustom/save/all/$output/dir3/file2") |
439
|
|
|
|
|
|
|
|| diag("TEST: supports wildcarding 3/4"); |
440
|
1
|
50
|
|
|
|
291
|
ok(-f "$output/.ncustom/save/tx1/$output/dir3/file2") |
441
|
|
|
|
|
|
|
|| diag("TEST: supports wildcarding 4/4"); |
442
|
|
|
|
|
|
|
# |
443
|
|
|
|
|
|
|
# extra tests |
444
|
|
|
|
|
|
|
# |
445
|
1
|
|
|
|
|
296
|
transaction("tx2"); |
446
|
1
|
|
|
|
|
301
|
save_files("~/dir4/file1"); |
447
|
1
|
50
|
|
|
|
319
|
ok(-f "$output/.ncustom/save/tx2/$output/dir4/file1") |
448
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
449
|
|
|
|
|
|
|
TEST: |
450
|
|
|
|
|
|
|
TEST: - saves to a corresponding tx archive when the tx changes 1/2 |
451
|
|
|
|
|
|
|
EOF |
452
|
1
|
50
|
|
|
|
8
|
ok(! -f "$output/.ncustom/save/tx1/$output/dir4/file1") |
453
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
454
|
|
|
|
|
|
|
TEST: |
455
|
|
|
|
|
|
|
TEST: - saves to a corresponding tx archive when the tx changes 2/2 |
456
|
|
|
|
|
|
|
EOF |
457
|
1
|
|
|
|
|
106
|
copy("$input/dir4file1.v2", "$output/dir4/file1"); |
458
|
1
|
|
|
|
|
1984
|
save_files("~/dir4/file1"); |
459
|
1
|
|
|
|
|
380
|
my @matches = glob("$output/.ncustom/save/tx2/$output/dir4/*"); |
460
|
1
|
50
|
|
|
|
470
|
is($#matches, 1) |
461
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
462
|
|
|
|
|
|
|
TEST: if a file is saved to an archive, and it is already there: |
463
|
|
|
|
|
|
|
TEST: - the file will be saved with a suffix |
464
|
|
|
|
|
|
|
EOF |
465
|
|
|
|
|
|
|
#this better test didnt work because of filename mangling with samba |
466
|
|
|
|
|
|
|
#ok(-f "$output/.ncustom/save/tx2/$output/dir4/file1.AT*") |
467
|
1
|
|
|
|
|
269
|
save_files("~/dir4/file1"); |
468
|
1
|
|
|
|
|
25
|
@matches = glob("$output/.ncustom/save/tx2/$output/dir4/*"); |
469
|
1
|
50
|
|
|
|
1053
|
is($#matches, 1) |
470
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
471
|
|
|
|
|
|
|
TEST: if a file is saved to an archive, and it is already there: |
472
|
|
|
|
|
|
|
TEST: - if there is no change it wont be saved again |
473
|
|
|
|
|
|
|
EOF |
474
|
1
|
|
|
|
|
194
|
output(); |
475
|
|
|
|
|
|
|
|
476
|
1
|
|
|
|
|
103
|
=cut |
477
|
1
|
|
|
|
|
867
|
|
478
|
|
|
|
|
|
|
#==================================================================== |
479
|
|
|
|
|
|
|
sub save_file; |
480
|
1
|
|
|
|
|
3
|
sub save_files { |
481
|
1
|
|
|
12
|
1
|
5
|
my ($files, @rest) = @_; |
|
0
|
|
|
|
|
0
|
|
482
|
140
|
|
|
|
|
721
|
my @lines = split(/\n/,$files); |
483
|
1
|
|
|
|
|
6
|
my $status = 1; |
|
12
|
|
|
|
|
67
|
|
484
|
1
|
|
|
|
|
5
|
my $line; |
|
12
|
|
|
|
|
75
|
|
485
|
1
|
|
|
|
|
4
|
|
486
|
12
|
|
|
|
|
41
|
foreach $line (@lines){ |
487
|
12
|
|
|
|
|
566
|
my ($file, @rest) = ($line =~ /\s*(.*)/); |
488
|
12
|
50
|
|
|
|
46
|
save_file($file) || ($status = 0); |
489
|
|
|
|
|
|
|
} |
490
|
13
|
|
|
|
|
170
|
return $status; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
#==================================================================== |
494
|
|
|
|
|
|
|
sub save_file2; |
495
|
|
|
|
|
|
|
sub expand_filenames; |
496
|
|
|
|
|
|
|
sub save_file { |
497
|
|
|
|
|
|
|
#save_file reduces the problem to dealing with indivudual files |
498
|
|
|
|
|
|
|
#it then calls save_file2 to do the work |
499
|
13
|
|
|
33
|
0
|
59
|
my ($file, @rest) = @_; |
500
|
12
|
|
|
|
|
193
|
my ($msg, $rc, $f, $global_dest, $local_dest); |
501
|
33
|
|
|
|
|
140
|
my $status = 1; |
502
|
|
|
|
|
|
|
|
503
|
33
|
|
|
|
|
80
|
foreach my $f ( expand_filenames($file)){ |
504
|
33
|
|
|
|
|
104
|
chomp $f; |
505
|
33
|
|
|
|
|
194
|
$global_dest = "$Config{'save_dir'}/all/$f"; |
506
|
35
|
|
|
|
|
128
|
$local_dest = "$Config{'save_dir'}/$Transaction/$f"; |
507
|
35
|
50
|
|
|
|
660
|
save_file2($f, $global_dest) || ($status =0); |
508
|
35
|
50
|
|
|
|
241
|
save_file2($f, $local_dest) || ($status =0); |
509
|
35
|
100
|
|
|
|
373
|
if(! -e $f){ |
510
|
1
|
|
|
|
|
2
|
#So we must be dealing with a new file. |
511
|
|
|
|
|
|
|
#For consistencey: |
512
|
35
|
100
|
|
|
|
233
|
-d "$Config{'save_dir'}/${Transaction}" |
513
|
1
|
|
|
|
|
161
|
|| mkpath "$Config{'save_dir'}/${Transaction}"; |
|
1
|
|
|
|
|
20
|
|
514
|
1
|
|
|
|
|
465
|
|
515
|
|
|
|
|
|
|
#We have a special place for noting new files: |
516
|
35
|
|
|
|
|
961
|
$global_dest = "$Config{'save_dir'}/all.new/$f"; |
517
|
11
|
|
|
|
|
3853
|
$rc = crud_gaurantee($global_dest,"create",\$msg); |
518
|
11
|
50
|
|
|
|
52
|
unless($rc){carp "save_file: $msg"; return 0; } |
|
11
|
|
|
|
|
185
|
|
|
11
|
|
|
|
|
112
|
|
519
|
0
|
|
|
|
|
0
|
open(TOUCH,"> $global_dest"); |
520
|
0
|
|
|
|
|
0
|
close(TOUCH); |
521
|
|
|
|
|
|
|
|
522
|
11
|
|
|
|
|
1590
|
$local_dest = "$Config{'save_dir'}/${Transaction}.new/$f"; |
523
|
11
|
|
|
|
|
197
|
$rc = crud_gaurantee($local_dest,"create",\$msg); |
524
|
11
|
50
|
|
|
|
72
|
unless($rc){carp "save_file: $msg"; return 0; } |
|
11
|
|
|
|
|
58
|
|
|
11
|
|
|
|
|
56
|
|
525
|
0
|
|
|
|
|
0
|
open(TOUCH,"> $local_dest"); |
526
|
0
|
|
|
|
|
0
|
close(TOUCH); |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
} |
529
|
11
|
|
|
|
|
1193
|
return $status; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
#==================================================================== |
533
|
|
|
|
|
|
|
sub save_file2 { |
534
|
11
|
|
|
70
|
0
|
193
|
my ($file, $dest, @rest) = @_; |
535
|
33
|
|
|
|
|
499
|
my $rc = 1; |
536
|
70
|
|
|
|
|
211
|
my $msg; |
537
|
70
|
|
|
|
|
613
|
my ($sec, $min, $hr) = (localtime)[0..2]; |
538
|
70
|
|
|
|
|
87
|
my $suffix = ".AT_$hr:$min:$sec" ;#also used in undo_file |
539
|
|
|
|
|
|
|
#TODO# $sec not fine grained enough, will get caught out one day |
540
|
|
|
|
|
|
|
|
541
|
70
|
100
|
|
|
|
3782
|
if(! -e $file){ |
542
|
|
|
|
|
|
|
#we dont save something that doesnt exist |
543
|
|
|
|
|
|
|
#but still relatively normal as we may be dealing with a new creation |
544
|
70
|
|
|
|
|
898
|
return 1; |
545
|
|
|
|
|
|
|
} |
546
|
70
|
50
|
66
|
|
|
4446
|
if((-e $dest) && (compare($dest, $file) == 0)){ |
547
|
|
|
|
|
|
|
#already saved and files are the same |
548
|
|
|
|
|
|
|
#TODO# add more checking here, -f, perms... |
549
|
|
|
|
|
|
|
#carp "save_file: not saving, as not changed since last save: $file"; |
550
|
22
|
|
|
|
|
184
|
return 1; |
551
|
|
|
|
|
|
|
} |
552
|
48
|
100
|
66
|
|
|
2811
|
if((-e $dest) && (compare($dest, $file) != 0)){ |
553
|
|
|
|
|
|
|
#already saved but files are different |
554
|
|
|
|
|
|
|
#better get a new name |
555
|
0
|
|
|
|
|
0
|
$dest = "${dest}$suffix"; |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
48
|
|
|
|
|
2646
|
$rc = crud_gaurantee($dest,"create",\$msg); |
559
|
4
|
50
|
|
|
|
851
|
unless($rc){carp "save_file2: $msg"; return 0; } |
|
48
|
|
|
|
|
446
|
|
|
48
|
|
|
|
|
278
|
|
560
|
|
|
|
|
|
|
|
561
|
0
|
|
|
|
|
0
|
$rc = copy($file, $dest); |
562
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "save_file2: copy failed: $file, $dest."; return 0; } |
|
48
|
|
|
|
|
776
|
|
|
48
|
|
|
|
|
71628
|
|
563
|
|
|
|
|
|
|
|
564
|
0
|
|
|
|
|
0
|
return 1; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
#==================================================================== |
567
|
|
|
|
|
|
|
sub expand_filenames { |
568
|
0
|
|
|
64
|
0
|
0
|
my ($file_list, @rest) = @_ ; |
569
|
48
|
|
|
|
|
317
|
my @result; |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
#tag# |
572
|
64
|
|
|
|
|
219
|
my @lines = split(/\n/,$file_list); |
573
|
64
|
|
|
|
|
117
|
foreach my $line (@lines){ |
574
|
64
|
|
|
|
|
307
|
$line =~ s/^\s+//; #trim leading whitespace |
575
|
64
|
50
|
|
|
|
187
|
next if $line =~ /^#/; #TODO# comments need much work |
576
|
|
|
|
|
|
|
#TODO# find the perl fn for the following kludge |
577
|
|
|
|
|
|
|
#cant use builtin glob as in some instances we're dealing with a newfile |
578
|
|
|
|
|
|
|
#(builtin glob matches existing) |
579
|
66
|
|
|
|
|
492
|
my @filename_expansion = split(/\s+/, `echo $line`); |
580
|
66
|
|
|
|
|
290
|
foreach my $filename (@filename_expansion){ |
581
|
66
|
|
|
|
|
626156
|
push @result, $filename; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
} |
584
|
66
|
|
|
|
|
2379
|
return @result; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
#==================================================================== |
588
|
|
|
|
|
|
|
# initialise |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=item C |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=begin example |
593
|
|
|
|
|
|
|
|
594
|
1
|
|
|
|
|
3
|
test_reset(); |
595
|
1
|
50
|
|
|
|
2
|
can_ok("NCustom", qw(initialise)) |
596
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=end example |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
=for example begin |
601
|
|
|
|
|
|
|
|
602
|
1
|
|
|
|
|
3
|
initialise(); |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=for example end |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
Initialise the archive of saved files. As this deletes files this is not done automatically. |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=for example_testing |
609
|
1
|
|
|
|
|
77
|
@matches = glob("$output/.ncustom/save/*"); |
610
|
1
|
50
|
|
|
|
1219
|
is($#matches, 3) # ie 4 entries (all, all.new, tx1, tx1.new) |
611
|
|
|
|
|
|
|
|| diag("TEST: removes all save files"); |
612
|
1
|
50
|
|
|
|
201
|
ok(-d "$output/.ncustom/save/all") |
613
|
|
|
|
|
|
|
|| diag("TEST: creates an empty skeleton save dir"); |
614
|
1
|
|
|
|
|
14
|
output(); |
615
|
|
|
|
|
|
|
|
616
|
1
|
|
|
|
|
626
|
=cut |
617
|
1
|
|
|
|
|
686
|
|
618
|
|
|
|
|
|
|
#==================================================================== |
619
|
|
|
|
|
|
|
sub initialise { |
620
|
1
|
50
|
|
1
|
1
|
2
|
rmtree($Config{'save_dir'}) || return 0; |
|
70
|
|
|
|
|
1559
|
|
621
|
1
|
50
|
|
|
|
7
|
mkpath("$Config{'save_dir'}/all") || return 0; |
|
64
|
|
|
|
|
1816
|
|
622
|
1
|
50
|
|
|
|
1150
|
mkpath("$Config{'save_dir'}/all.new") || return 0; |
623
|
1
|
50
|
|
|
|
6
|
mkpath("$Config{'save_dir'}/$Transaction") || return 0; |
|
1
|
|
|
|
|
387
|
|
624
|
1
|
50
|
|
|
|
3
|
mkpath("$Config{'save_dir'}/${Transaction}.new") || return 0; |
|
1
|
|
|
|
|
141
|
|
625
|
1
|
50
|
|
|
|
6
|
rmtree($Config{'tmp_dir'}) || return 0; |
|
1
|
|
|
|
|
160
|
|
626
|
1
|
50
|
|
|
|
126
|
mkpath($Config{'tmp_dir'}) || return 0; |
627
|
1
|
|
|
|
|
280
|
return 1; |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
#==================================================================== |
631
|
|
|
|
|
|
|
# commit_file |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=begin testing |
634
|
|
|
|
|
|
|
|
635
|
1
|
|
|
|
|
3
|
test_reset(); |
636
|
|
|
|
|
|
|
|
637
|
1
|
|
|
|
|
3
|
my $tmp = "$NCustom::Config{'tmp_dir'}"; |
638
|
|
|
|
|
|
|
#use tmp for files that will be altered/moved (to keep input unaltered) |
639
|
|
|
|
|
|
|
|
640
|
1
|
|
|
|
|
4
|
copy("$input/dir5file1", "$tmp/dir5file1"); |
641
|
1
|
|
|
|
|
47
|
&NCustom::commit_file("$tmp/dir5file1", "$output/dir5/file1"); |
642
|
1
|
50
|
|
|
|
63
|
ok(-f "$output/dir5/file1") |
643
|
|
|
|
|
|
|
|| diag("TEST: checks in a new file"); |
644
|
1
|
50
|
|
|
|
625
|
ok(! -f "$output/.ncustom/save/tx1/$output/dir5/file1") |
645
|
|
|
|
|
|
|
|| diag("TEST: doesnt archive files that didnt already exist"); |
646
|
|
|
|
|
|
|
#TODO# that is interesting, that means that restore wont delete it |
647
|
|
|
|
|
|
|
#TODO# could handle by save archiving filename.new, the resore knows to rm |
648
|
|
|
|
|
|
|
|
649
|
1
|
|
|
|
|
213
|
copy("$input/dir5file1.v2", "$tmp/dir5file1.v2"); |
650
|
1
|
|
|
|
|
1715
|
&NCustom::commit_file("$tmp/dir5file1.v2", "$output/dir5/file1"); |
651
|
1
|
50
|
|
|
|
551
|
is(compare("$output/dir5/file1", "$input/dir5file1.v2"), 0) |
652
|
|
|
|
|
|
|
|| diag("TEST: checks in over an existing file"); |
653
|
1
|
50
|
|
|
|
1096
|
is(compare("$output/.ncustom/save/tx1/$output/dir5/file1","$input/dir5file1"), 0) |
654
|
|
|
|
|
|
|
|| diag("TEST: saves things before it clobbers them"); |
655
|
|
|
|
|
|
|
|
656
|
1
|
|
|
|
|
21
|
copy("$input/dir5file1", "$tmp/dir5file1"); |
657
|
1
|
|
|
|
|
868
|
&NCustom::commit_file("$tmp/dir5file1", "$output/dir5/subdir1/file1"); |
658
|
1
|
50
|
|
|
|
549
|
ok(-f "$output/dir5/subdir1/file1") |
659
|
|
|
|
|
|
|
|| diag("TEST: checks in a new file, creating subdirs required"); |
660
|
1
|
|
|
|
|
375
|
output(); |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=end testing |
663
|
1
|
|
|
|
|
56
|
|
664
|
1
|
|
|
|
|
1013
|
=cut |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
#==================================================================== |
667
|
|
|
|
|
|
|
sub commit_file{ |
668
|
1
|
|
|
20
|
0
|
8
|
my($newfile, $file, @rest) = @_ ; |
|
1
|
|
|
|
|
11
|
|
|
1
|
|
|
|
|
145
|
|
669
|
1
|
|
|
|
|
11
|
my $rc = 1; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
670
|
20
|
|
|
|
|
331
|
my $msg; |
671
|
|
|
|
|
|
|
|
672
|
1
|
|
|
|
|
232
|
$rc = crud_gaurantee($newfile,"read delete",\$msg); |
|
1
|
|
|
|
|
19
|
|
|
20
|
|
|
|
|
64
|
|
673
|
1
|
50
|
|
|
|
624
|
unless($rc){carp "commit_file: $msg"; return 0; } |
|
20
|
|
|
|
|
41
|
|
|
20
|
|
|
|
|
114
|
|
|
20
|
|
|
|
|
314
|
|
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
0
|
$rc = crud_gaurantee($file,"create",\$msg); |
676
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "commit_file: $msg"; return 0; } |
|
20
|
|
|
|
|
147
|
|
|
20
|
|
|
|
|
88
|
|
677
|
|
|
|
|
|
|
|
678
|
0
|
|
|
|
|
0
|
$rc = save_file($file); |
679
|
0
|
50
|
|
|
|
0
|
unless($rc){ carp "commit_file: save_file: $file failed\n"; return 0; } |
|
20
|
|
|
|
|
82
|
|
|
20
|
|
|
|
|
68
|
|
680
|
|
|
|
|
|
|
|
681
|
0
|
|
|
|
|
0
|
$rc = copy($newfile, $file); |
682
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "commit_file: copy failed: $newfile, $file.\n"; return 0;} |
|
20
|
|
|
|
|
352
|
|
|
20
|
|
|
|
|
13624
|
|
683
|
|
|
|
|
|
|
|
684
|
0
|
|
|
|
|
0
|
$rc = unlink($newfile); |
685
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "commit_file: unlink failed: $newfile.\n"; return 0;} |
|
20
|
|
|
|
|
2939
|
|
|
20
|
|
|
|
|
85
|
|
686
|
|
|
|
|
|
|
|
687
|
0
|
|
|
|
|
0
|
return 1; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
#==================================================================== |
691
|
|
|
|
|
|
|
# overwrite_file |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=item C |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=begin example |
696
|
|
|
|
|
|
|
|
697
|
1
|
|
|
|
|
3
|
test_reset(); |
698
|
1
|
50
|
|
|
|
3
|
can_ok("NCustom", qw(overwrite_file)) |
699
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=end example |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=for example begin |
704
|
|
|
|
|
|
|
|
705
|
1
|
|
|
|
|
7
|
overwrite_file(file => "~/dir6/file1", text => ' some content'); |
706
|
|
|
|
|
|
|
|
707
|
1
|
|
|
|
|
89
|
overwrite_file(file => "~/dir6/file2", |
708
|
|
|
|
|
|
|
strip => '^\s{4}', |
709
|
|
|
|
|
|
|
text => <<' EOF'); |
710
|
|
|
|
|
|
|
This will be line 1 of the new content of the file. |
711
|
|
|
|
|
|
|
This will be line 2 of the new content of the file. |
712
|
|
|
|
|
|
|
This, line3, will still be indented. As will line 4. |
713
|
|
|
|
|
|
|
I bet there will be a dollar sign and two single quotes on the next line. |
714
|
|
|
|
|
|
|
'I told you so ! Now you owe me $20', I would then say. |
715
|
|
|
|
|
|
|
This will be the last line. |
716
|
|
|
|
|
|
|
EOF |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=for example end |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
Overwrite file overwrites $file with $text. |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
So that you can have pretty indentation when using here documents, the pattern $strip is stripped out prior to processing. |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
More clearly, overwrite file is equivalent to: |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
open(FILE,">$file"); |
727
|
|
|
|
|
|
|
$text =~ s/$strip//; |
728
|
|
|
|
|
|
|
print FILE $text; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=for example_testing |
731
|
1
|
50
|
|
|
|
1299
|
is(compare("$output/dir6/file1", "$input/dir6file1.v2"), 0) |
732
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
733
|
|
|
|
|
|
|
TEST: |
734
|
|
|
|
|
|
|
TEST: - is logically equivalent to ">" |
735
|
|
|
|
|
|
|
TEST: - will not strip anything by default |
736
|
|
|
|
|
|
|
TEST: - performs filename expansion eg ~/ |
737
|
|
|
|
|
|
|
TEST: - will create new file if required |
738
|
|
|
|
|
|
|
EOF |
739
|
1
|
50
|
|
|
|
18
|
is(compare("$output/dir6/file2", "$input/dir6file2.v2"), 0) |
740
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
741
|
|
|
|
|
|
|
TEST: |
742
|
|
|
|
|
|
|
TEST: - will strip a given pattern from the text |
743
|
|
|
|
|
|
|
EOF |
744
|
1
|
|
|
|
|
39
|
overwrite_file(file => "~/dir6/subdir1/file1", text => ' some content'); |
745
|
1
|
50
|
|
|
|
884
|
is(compare("$output/dir6/subdir1/file1", "$input/dir6file1.v2"), 0) |
746
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
747
|
|
|
|
|
|
|
TEST: |
748
|
|
|
|
|
|
|
TEST: - will create subdirs as needed for new files |
749
|
|
|
|
|
|
|
EOF |
750
|
1
|
|
|
|
|
477
|
output(); |
751
|
|
|
|
|
|
|
|
752
|
1
|
|
|
|
|
37
|
=cut |
753
|
1
|
|
|
|
|
871
|
|
754
|
|
|
|
|
|
|
#==================================================================== |
755
|
|
|
|
|
|
|
sub change_file { |
756
|
1
|
|
|
15
|
0
|
92
|
my %args = @_ ; |
|
0
|
|
|
|
|
0
|
|
757
|
1
|
|
50
|
|
|
6
|
my $change = ($args{'change'} || ""); |
|
20
|
|
|
|
|
567
|
|
758
|
15
|
|
50
|
|
|
149
|
my $files = ($args{'files'} || ""); |
759
|
1
|
|
50
|
|
|
2
|
my $body = ($args{'body'} || ""); |
|
15
|
|
|
|
|
72
|
|
760
|
1
|
|
100
|
|
|
8
|
my $strip = ($args{'strip'} || ""); |
|
15
|
|
|
|
|
56
|
|
761
|
1
|
|
|
|
|
6
|
my $status = 1; |
|
15
|
|
|
|
|
57
|
|
762
|
15
|
|
|
|
|
147
|
my $rc = 1; |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
# input checks |
765
|
15
|
50
|
|
|
|
24
|
if($files eq ""){ |
766
|
15
|
|
|
|
|
26
|
carp "change_file: file name is blank.\n"; return 0; |
|
15
|
|
|
|
|
48
|
|
767
|
|
|
|
|
|
|
} |
768
|
0
|
50
|
|
|
|
0
|
if($change !~ /^(overwrite|append|prepend|edit)$/){ |
769
|
0
|
|
|
|
|
0
|
carp "change_file: Invalid type of change: $change."; return 0; |
|
15
|
|
|
|
|
319
|
|
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# pre-process body (text / code) |
773
|
0
|
100
|
|
|
|
0
|
$body =~ s/$strip//mg unless $strip eq ""; |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# pre-process filenames |
776
|
|
|
|
|
|
|
# then invoke processing on each one |
777
|
0
|
|
|
|
|
0
|
foreach my $file (expand_filenames($files)){ |
778
|
15
|
|
|
|
|
542
|
chomp $file; |
779
|
15
|
|
|
|
|
191
|
$rc = change_file2(change => $change, file => $file, body => $body); |
780
|
17
|
50
|
|
|
|
116
|
unless($rc){$status = 0}; |
|
17
|
|
|
|
|
147
|
|
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
|
783
|
17
|
|
|
|
|
216
|
return $status; |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
#==================================================================== |
787
|
|
|
|
|
|
|
sub change_file2 { |
788
|
0
|
|
|
17
|
0
|
0
|
my %args = @_ ; |
789
|
15
|
|
50
|
|
|
477
|
my $change = ($args{'change'} || ""); |
790
|
17
|
|
50
|
|
|
587
|
my $file = ($args{'file'} || ""); |
791
|
17
|
|
50
|
|
|
199
|
my $body = ($args{'body'} || ""); |
792
|
17
|
|
|
|
|
214
|
my $rc = 1; |
793
|
17
|
|
|
|
|
72
|
my $msg = ""; |
794
|
1
|
|
|
|
|
3
|
|
795
|
|
|
|
|
|
|
#we use a tmp file |
796
|
17
|
|
|
|
|
42
|
my $newfile = "$Config{'tmp_dir'}/" . basename($file); |
797
|
1
|
|
|
|
|
193
|
$rc = crud_gaurantee($newfile, "create", \$msg); |
|
1
|
|
|
|
|
19
|
|
|
17
|
|
|
|
|
169
|
|
798
|
1
|
50
|
|
|
|
528
|
unless($rc){carp "change_file2: $msg"; return 0; } |
|
17
|
|
|
|
|
4591
|
|
|
17
|
|
|
|
|
702
|
|
|
17
|
|
|
|
|
84
|
|
799
|
|
|
|
|
|
|
|
800
|
0
|
100
|
|
|
|
0
|
if($change =~ /overwrite/ ){ |
801
|
0
|
|
|
|
|
0
|
$rc = open(NEWFILE, ">$newfile"); |
802
|
17
|
|
|
|
|
136
|
print NEWFILE $body ; |
803
|
6
|
|
|
|
|
825
|
close(NEWFILE); |
804
|
|
|
|
|
|
|
} |
805
|
6
|
100
|
|
|
|
60
|
if($change =~ /append/ ){ |
806
|
6
|
100
|
|
|
|
415
|
if( -e $file){ |
807
|
17
|
|
|
|
|
120
|
$rc = crud_gaurantee($file, "read", \$msg); |
808
|
3
|
50
|
|
|
|
121
|
unless($rc){carp "change_file2: $msg"; return 0; } |
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
13
|
|
809
|
0
|
|
|
|
|
0
|
copy($file, $newfile); |
810
|
|
|
|
|
|
|
} |
811
|
0
|
|
|
|
|
0
|
open(NEWFILE, ">>$newfile"); |
812
|
1
|
|
|
|
|
347
|
print NEWFILE $body ; |
813
|
3
|
|
|
|
|
1568
|
close(NEWFILE); |
814
|
|
|
|
|
|
|
} |
815
|
3
|
100
|
|
|
|
32
|
if($change =~ /prepend/ ){ |
816
|
3
|
|
|
|
|
180
|
open(NEWFILE, ">$newfile"); |
817
|
17
|
|
|
|
|
818
|
print NEWFILE $body ; |
818
|
3
|
|
|
|
|
603
|
close(NEWFILE); |
819
|
3
|
100
|
|
|
|
38
|
-f $file && system("cat $file >> $newfile"); #TODO# do in perl |
820
|
|
|
|
|
|
|
} |
821
|
3
|
100
|
|
|
|
216
|
if($change =~ /edit/ ){ |
822
|
3
|
|
|
|
|
23112
|
$rc = crud_gaurantee($file, "read", \$msg); |
823
|
17
|
50
|
|
|
|
126
|
unless($rc){carp "change_file2: $msg"; return 0; } |
|
5
|
|
|
|
|
45
|
|
|
5
|
|
|
|
|
48
|
|
824
|
0
|
|
|
|
|
0
|
open(FILE, "<$file"); |
825
|
0
|
|
|
|
|
0
|
open(NEWFILE, ">$newfile"); |
826
|
|
|
|
|
|
|
# select newfile, so prints in $body behave as expected |
827
|
5
|
|
|
|
|
350
|
my $old_fh = select(NEWFILE); |
828
|
|
|
|
|
|
|
# the action |
829
|
2
|
|
|
2
|
|
3569
|
no strict; no warnings ; |
|
2
|
|
|
2
|
|
13
|
|
|
2
|
|
|
|
|
6863
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
88
|
|
|
2
|
|
|
|
|
12
|
|
830
|
5
|
|
|
|
|
594
|
while( ){ |
831
|
5
|
|
|
|
|
57
|
eval $body; |
832
|
5
|
50
|
|
|
|
93
|
if($@){carp "change_file2: code \n$body \nraised the error $@"; return 0;} |
|
17
|
|
|
|
|
2253
|
|
|
17
|
|
|
|
|
83
|
|
833
|
|
|
|
|
|
|
} continue { |
834
|
0
|
|
|
|
|
0
|
print; |
835
|
|
|
|
|
|
|
} |
836
|
2
|
|
|
2
|
|
4
|
use strict; use warnings; |
|
2
|
|
|
2
|
|
216
|
|
|
2
|
|
|
|
|
41
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
72
|
|
|
2
|
|
|
|
|
12
|
|
837
|
0
|
|
|
|
|
0
|
close(NEWFILE); |
838
|
17
|
|
|
|
|
154
|
close(FILE); |
839
|
5
|
|
|
|
|
391
|
select($old_fh); |
840
|
|
|
|
|
|
|
} |
841
|
|
|
|
|
|
|
|
842
|
5
|
|
|
|
|
48
|
return commit_file($newfile, $file); |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
#==================================================================== |
846
|
|
|
|
|
|
|
sub overwrite_file { |
847
|
5
|
|
|
6
|
1
|
47
|
my %args = @_ ; |
848
|
17
|
|
50
|
|
|
121
|
my $file = ($args{'file'} || ""); |
849
|
6
|
|
50
|
|
|
65
|
my $text = ($args{'text'} || ""); |
850
|
6
|
|
100
|
|
|
35
|
my $strip = ($args{'strip'} || ""); |
851
|
|
|
|
|
|
|
|
852
|
6
|
|
|
|
|
29
|
return change_file(change => "overwrite", files => $file, |
853
|
|
|
|
|
|
|
body => $text, strip => $strip); |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
#==================================================================== |
857
|
|
|
|
|
|
|
# append_file |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=item C |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
=begin example |
862
|
|
|
|
|
|
|
|
863
|
1
|
|
|
|
|
3
|
test_reset(); |
864
|
1
|
50
|
|
|
|
6
|
can_ok("NCustom", qw(append_file)) |
865
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
=end example |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=for example begin |
870
|
|
|
|
|
|
|
|
871
|
1
|
|
|
|
|
5
|
append_file(file => "~/dir7/file1", text => 'an extra line'); |
872
|
|
|
|
|
|
|
|
873
|
1
|
|
|
|
|
83
|
append_file(file => "~/dir7/file2", |
874
|
|
|
|
|
|
|
strip => '^\s{4}', |
875
|
|
|
|
|
|
|
text => <<' EOF'); |
876
|
|
|
|
|
|
|
An extra line to add on to the file. |
877
|
|
|
|
|
|
|
This line, will be indented. |
878
|
|
|
|
|
|
|
The last last line with some special chars *!@$%.'" |
879
|
|
|
|
|
|
|
EOF |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
=for example end |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
Append file is the same as overwrite file, except it behaves as ">>" instead of ">". |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
=for example_testing |
886
|
1
|
50
|
|
|
|
1371
|
is(compare("$output/dir7/file1", "$input/dir7file1.v2"), 0) |
887
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
888
|
|
|
|
|
|
|
TEST: |
889
|
|
|
|
|
|
|
TEST: - is logically equivalent to ">>" |
890
|
|
|
|
|
|
|
TEST: - will not strip anything by default |
891
|
|
|
|
|
|
|
TEST: - performs filename expansion eg ~/ |
892
|
|
|
|
|
|
|
TEST: - will create new file if required |
893
|
|
|
|
|
|
|
EOF |
894
|
1
|
50
|
|
|
|
21
|
is(compare("$output/dir7/file2", "$input/dir7file2.v2"), 0) |
895
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
896
|
|
|
|
|
|
|
TEST: |
897
|
|
|
|
|
|
|
TEST: - will strip a given pattern from the text |
898
|
|
|
|
|
|
|
EOF |
899
|
1
|
|
|
|
|
40
|
append_file(file => "~/dir7/subdir1/file1", text => 'an extra line'); |
900
|
1
|
50
|
|
|
|
926
|
is(compare("$output/dir7/subdir1/file1", "$input/dir7file1.v2"), 0) |
901
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
902
|
|
|
|
|
|
|
TEST: |
903
|
|
|
|
|
|
|
TEST: - will create subdirs as needed for new files |
904
|
|
|
|
|
|
|
EOF |
905
|
1
|
|
|
|
|
499
|
output(); |
906
|
|
|
|
|
|
|
|
907
|
1
|
|
|
|
|
32
|
=cut |
908
|
1
|
|
|
|
|
1637
|
|
909
|
|
|
|
|
|
|
#==================================================================== |
910
|
|
|
|
|
|
|
sub append_file { |
911
|
1
|
|
|
3
|
1
|
2
|
my %args = @_ ; |
|
6
|
|
|
|
|
57
|
|
912
|
1
|
|
50
|
|
|
5
|
my $file = ($args{'file'} || ""); |
|
6
|
|
|
|
|
42
|
|
913
|
3
|
|
50
|
|
|
35
|
my $text = ($args{'text'} || ""); |
914
|
1
|
|
100
|
|
|
5
|
my $strip = ($args{'strip'} || ""); |
|
3
|
|
|
|
|
22
|
|
915
|
1
|
|
|
|
|
5
|
|
916
|
1
|
|
|
|
|
4
|
return change_file(change => "append", files => $file, |
|
3
|
|
|
|
|
25
|
|
917
|
|
|
|
|
|
|
body => $text, strip => $strip); |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
#==================================================================== |
921
|
|
|
|
|
|
|
# prepend_file |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
=item C |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=begin example |
926
|
|
|
|
|
|
|
|
927
|
1
|
|
|
|
|
3
|
test_reset(); |
928
|
1
|
50
|
|
|
|
5
|
can_ok("NCustom", qw(prepend_file)) |
929
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=end example |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
=for example begin |
934
|
|
|
|
|
|
|
|
935
|
1
|
|
|
|
|
6
|
prepend_file(file => "~/dir8/file1", text => 'an extra line'); |
936
|
|
|
|
|
|
|
|
937
|
1
|
|
|
|
|
115
|
prepend_file(file => "~/dir8/file2", |
938
|
|
|
|
|
|
|
strip => '^\s{4}', |
939
|
|
|
|
|
|
|
text => <<' EOF'); |
940
|
|
|
|
|
|
|
An extra line at the start of the file. |
941
|
|
|
|
|
|
|
This line, will be indented. |
942
|
|
|
|
|
|
|
Some special chars *!@$%.'" |
943
|
|
|
|
|
|
|
The last extra line added to the start of the file. |
944
|
|
|
|
|
|
|
EOF |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
=for example end |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
Prepend behaves the same as append, except the text is added to the start instead of the end. |
949
|
|
|
|
|
|
|
|
950
|
1
|
|
|
|
|
2
|
=for example_testing |
951
|
1
|
50
|
|
|
|
2080
|
is(compare("$output/dir8/file1", "$input/dir8file1.v2"), 0) |
952
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
953
|
1
|
|
|
|
|
206
|
TEST: |
|
1
|
|
|
|
|
18
|
|
954
|
1
|
|
|
|
|
490
|
TEST: - is logically equivalent to ">>" |
955
|
|
|
|
|
|
|
TEST: - will not strip anything by default |
956
|
|
|
|
|
|
|
TEST: - performs filename expansion eg ~/ |
957
|
|
|
|
|
|
|
TEST: - will create new file if required |
958
|
|
|
|
|
|
|
EOF |
959
|
1
|
50
|
|
|
|
30
|
is(compare("$output/dir8/file2", "$input/dir8file2.v2"), 0) |
960
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
961
|
|
|
|
|
|
|
TEST: |
962
|
|
|
|
|
|
|
TEST: - will strip a given pattern from the text |
963
|
|
|
|
|
|
|
EOF |
964
|
1
|
|
|
|
|
42
|
prepend_file(file => "~/dir8/subdir1/file1", text => 'an extra line'); |
965
|
1
|
50
|
|
|
|
1057
|
is(compare("$output/dir8/subdir1/file1", "$input/dir8file1.v2"), 0) |
966
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
967
|
|
|
|
|
|
|
TEST: |
968
|
|
|
|
|
|
|
TEST: - will create subdirs as needed for new files |
969
|
|
|
|
|
|
|
EOF |
970
|
1
|
|
|
|
|
573
|
output(); |
971
|
|
|
|
|
|
|
|
972
|
1
|
|
|
|
|
42
|
=cut |
973
|
1
|
|
|
|
|
793
|
|
974
|
|
|
|
|
|
|
#==================================================================== |
975
|
|
|
|
|
|
|
sub prepend_file { |
976
|
1
|
|
|
3
|
1
|
4
|
my %args = @_ ; |
|
3
|
|
|
|
|
34
|
|
977
|
1
|
|
50
|
|
|
10
|
my $file = ($args{'file'} || ""); |
|
3
|
|
|
|
|
31
|
|
978
|
3
|
|
50
|
|
|
47
|
my $text = ($args{'text'} || ""); |
979
|
1
|
|
100
|
|
|
7
|
my $strip = ($args{'strip'} || ""); |
|
3
|
|
|
|
|
25
|
|
980
|
1
|
|
|
|
|
3
|
|
981
|
1
|
|
|
|
|
7
|
return change_file(change => "prepend", files => $file, |
|
3
|
|
|
|
|
18
|
|
982
|
|
|
|
|
|
|
body => $text, strip => $strip); |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
#==================================================================== |
986
|
|
|
|
|
|
|
# edit_file |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
=item C |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
=begin example |
991
|
|
|
|
|
|
|
|
992
|
1
|
|
|
|
|
3
|
test_reset(); |
993
|
1
|
50
|
|
|
|
7
|
can_ok("NCustom", qw(edit_file)) |
994
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=end example |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
=for example begin |
999
|
|
|
|
|
|
|
|
1000
|
1
|
|
|
|
|
9
|
edit_file(file => "~/dir9/file1", code => 's/file/FILE/g;'); |
1001
|
|
|
|
|
|
|
|
1002
|
1
|
|
|
|
|
79
|
edit_file(file => "~/dir9/file2", |
1003
|
|
|
|
|
|
|
strip => '^\s{4}', |
1004
|
|
|
|
|
|
|
code => <<' EOF'); |
1005
|
|
|
|
|
|
|
s/my\.example\.com/whatever\.com/g; |
1006
|
|
|
|
|
|
|
s/^$/replace all blank lines with these three lines |
1007
|
|
|
|
|
|
|
two of three, with 4 leading spaces |
1008
|
|
|
|
|
|
|
and three of three/ ; |
1009
|
|
|
|
|
|
|
s/might/WILL/g; |
1010
|
|
|
|
|
|
|
EOF |
1011
|
|
|
|
|
|
|
|
1012
|
1
|
|
|
|
|
1369
|
edit_file(file => <<' EOF', strip => '^\s{6}', code => <<' EOF'); |
1013
|
|
|
|
|
|
|
~/dir9/file3 |
1014
|
|
|
|
|
|
|
~/dir10/* |
1015
|
|
|
|
|
|
|
EOF |
1016
|
|
|
|
|
|
|
s/file/FILE/g; |
1017
|
|
|
|
|
|
|
s/least/LEASTWAYS/g; |
1018
|
|
|
|
|
|
|
EOF |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
=for example end |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
Edit file is similar to: |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
perl -i -e "$code" $file |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
With edit file, $file must exist. |
1027
|
|
|
|
|
|
|
As with the other routines, $code has the pattern $strip stripped out. |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
You can also provide multiple filenames to be editted. This holds true for the other routines too. |
1030
|
|
|
|
|
|
|
|
1031
|
1
|
|
|
|
|
7
|
=for example_testing |
1032
|
1
|
50
|
|
|
|
22
|
is(compare("$output/dir9/file1", "$input/dir9file1.v2"), 0) |
1033
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
1034
|
1
|
|
|
|
|
241
|
TEST: |
|
1
|
|
|
|
|
16
|
|
1035
|
1
|
|
|
|
|
459
|
TEST: - simple edit file |
1036
|
|
|
|
|
|
|
EOF |
1037
|
|
|
|
|
|
|
# |
1038
|
1
|
50
|
|
|
|
18
|
is(compare("$output/dir9/file2", "$input/dir9file2.v2"), 0) |
1039
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
1040
|
|
|
|
|
|
|
TEST: |
1041
|
|
|
|
|
|
|
TEST: - multi substitution edit |
1042
|
|
|
|
|
|
|
EOF |
1043
|
1
|
50
|
|
|
|
36
|
is(compare("$output/dir9/file3", "$input/dir9file3.v2"), 0) |
1044
|
|
|
|
|
|
|
|| diag("TEST: - edits multiple files 1/3."); |
1045
|
1
|
50
|
|
|
|
831
|
is(compare("$output/dir10/file1", "$input/dir10file1.v2"), 0) |
1046
|
|
|
|
|
|
|
|| diag("TEST: - edits multiple files 2/3."); |
1047
|
1
|
50
|
|
|
|
500
|
is(compare("$output/dir10/file2", "$input/dir10file2.v2"), 0) |
1048
|
|
|
|
|
|
|
|| diag("TEST: - edits multiple files 3/3."); |
1049
|
|
|
|
|
|
|
# |
1050
|
1
|
|
|
|
|
471
|
output(); |
1051
|
|
|
|
|
|
|
|
1052
|
1
|
|
|
|
|
536
|
=cut |
1053
|
1
|
|
|
|
|
559
|
|
1054
|
|
|
|
|
|
|
#==================================================================== |
1055
|
|
|
|
|
|
|
sub edit_file { |
1056
|
1
|
|
|
3
|
1
|
2
|
my %args = @_ ; |
|
3
|
|
|
|
|
35
|
|
1057
|
1
|
|
50
|
|
|
2
|
my $file = ($args{'file'} || ""); |
|
3
|
|
|
|
|
29
|
|
1058
|
3
|
|
50
|
|
|
39
|
my $code = ($args{'code'} || ""); |
1059
|
1
|
|
100
|
|
|
6
|
my $strip = ($args{'strip'} || ""); |
|
3
|
|
|
|
|
23
|
|
1060
|
1
|
|
|
|
|
2
|
|
1061
|
1
|
|
|
|
|
4
|
return change_file(change => "edit", files => $file, |
|
3
|
|
|
|
|
24
|
|
1062
|
|
|
|
|
|
|
body => $code, strip => $strip); |
1063
|
|
|
|
|
|
|
} |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
#==================================================================== |
1066
|
|
|
|
|
|
|
# undo_files |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
=item C |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
=begin example |
1071
|
|
|
|
|
|
|
|
1072
|
1
|
|
|
|
|
7
|
test_reset(); |
1073
|
1
|
50
|
|
|
|
3
|
can_ok("NCustom", qw(undo_files)) |
1074
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1075
|
1
|
|
|
|
|
5
|
save_files("~/dir11/file1 ~/dir11/file2"); |
1076
|
1
|
|
|
|
|
84
|
transaction("tx2"); |
1077
|
1
|
|
|
|
|
1716
|
save_files("~/dir11/file3"); |
1078
|
1
|
|
|
|
|
32
|
transaction("tx3"); |
1079
|
1
|
|
|
|
|
16
|
save_files("~/dir11/file4"); |
1080
|
1
|
|
|
|
|
22
|
transaction("tx4"); |
1081
|
1
|
|
|
|
|
11
|
save_files("~/dir11/file5"); |
1082
|
1
|
|
|
|
|
35
|
transaction("tx5"); |
1083
|
1
|
|
|
|
|
12
|
save_files("~/dir11/file6"); |
1084
|
1
|
|
|
|
|
32
|
transaction("tx6"); |
1085
|
1
|
|
|
|
|
18
|
save_files("~/dir11/file7"); |
1086
|
1
|
|
|
|
|
26
|
transaction("tx7"); |
1087
|
1
|
|
|
|
|
16
|
save_files("~/dir11/file8"); |
1088
|
1
|
|
|
|
|
19
|
rmtree("$output/dir11"); |
1089
|
1
|
|
|
|
|
13
|
mkpath("$output/dir11"); |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
=end example |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
=for example begin |
1094
|
|
|
|
|
|
|
|
1095
|
1
|
|
|
|
|
1826
|
undo_files("tx1"); |
1096
|
|
|
|
|
|
|
|
1097
|
1
|
|
|
|
|
197
|
undo_files("~/.ncustom/save/tx2"); |
1098
|
|
|
|
|
|
|
|
1099
|
1
|
|
|
|
|
14
|
undo_files("tx3 tx4"); |
1100
|
|
|
|
|
|
|
|
1101
|
1
|
|
|
|
|
20
|
undo_files(<<' EOF'); |
1102
|
|
|
|
|
|
|
tx5 |
1103
|
|
|
|
|
|
|
~/.ncustom/save/tx6 |
1104
|
|
|
|
|
|
|
EOF |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=for example end |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
Undo transaction will restore the files from a given transaction archive directory. That includes removing any new files that were created. For any directories that it cannot find, it will try looking in $Config{'save_dir'}. |
1109
|
|
|
|
|
|
|
Undo does not: restore files that were edited by non-NCustom function if they were not first saved using NCuston::save_files; delete new directories that were created (yet). |
1110
|
|
|
|
|
|
|
Again: this is only a development aid. |
1111
|
|
|
|
|
|
|
|
1112
|
1
|
|
|
|
|
2
|
=for example_testing |
1113
|
1
|
50
|
33
|
|
|
20
|
ok(-f "$output/dir11/file1" && -f "$output/dir11/file2") |
1114
|
|
|
|
|
|
|
|| diag("TEST: restores files for a given customisation"); |
1115
|
1
|
50
|
|
|
|
320
|
ok(-f "$output/dir11/file3") |
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
21
|
|
1116
|
1
|
|
|
|
|
429
|
|| diag("TEST: restores files for a given directory"); |
1117
|
1
|
50
|
33
|
|
|
106
|
ok(-f "$output/dir11/file4" && -f "$output/dir11/file5") |
1118
|
|
|
|
|
|
|
|| diag("TEST: restores for multiple customisations at once"); |
1119
|
1
|
50
|
33
|
|
|
969
|
ok(-f "$output/dir11/file6" && -f "$output/dir11/file7") |
1120
|
|
|
|
|
|
|
|| diag("TEST: handles mixed multi-line arguments"); |
1121
|
1
|
50
|
|
|
|
511
|
ok(!-f "$output/dir11/file8") |
1122
|
|
|
|
|
|
|
|| diag("TEST: doesnt restore too much"); |
1123
|
1
|
|
|
|
|
405
|
undo_files("all"); |
1124
|
1
|
50
|
|
|
|
362
|
ok(-f "$output/dir11/file8") |
1125
|
|
|
|
|
|
|
|| diag("TEST: will restore all"); |
1126
|
1
|
|
|
|
|
412
|
transaction("tx8"); |
1127
|
1
|
|
|
|
|
56
|
mkpath("$output/dir12/subdir1"); |
1128
|
1
|
|
|
|
|
921
|
overwrite_file(file => "~/dir12/file1", text => ' some content'); |
1129
|
1
|
|
|
|
|
413
|
transaction("tx9"); |
1130
|
1
|
|
|
|
|
11
|
overwrite_file(file => "~/dir12/file2", text => ' some content'); |
1131
|
1
|
|
|
|
|
25
|
transaction("tx10"); |
1132
|
1
|
|
|
|
|
15
|
overwrite_file(file => "~/dir12/file3", text => ' some content'); |
1133
|
1
|
50
|
33
|
|
|
30
|
ok( -f "$output/dir12/file1" |
1134
|
|
|
|
|
|
|
&& -f "$output/dir12/file2" |
1135
|
|
|
|
|
|
|
&& -f "$output/dir12/file3") |
1136
|
|
|
|
|
|
|
|| diag("TEST: new files are setup ready for undo test"); |
1137
|
1
|
|
|
|
|
12
|
undo_files("tx8"); |
1138
|
1
|
50
|
|
|
|
208
|
ok(! -f "$output/dir12/file1") |
1139
|
|
|
|
|
|
|
|| diag("TEST: removes newly created files"); |
1140
|
1
|
50
|
33
|
|
|
887
|
ok(-f "$output/dir12/file2" && -f "$output/dir12/file3") |
1141
|
|
|
|
|
|
|
|| diag("TEST: doesnt removes too much"); |
1142
|
1
|
|
|
|
|
44
|
undo_files("all"); |
1143
|
1
|
50
|
33
|
|
|
951
|
ok( ! -f "$output/dir12/file1" |
1144
|
|
|
|
|
|
|
&& ! -f "$output/dir12/file2" |
1145
|
|
|
|
|
|
|
&& ! -f "$output/dir12/file3") |
1146
|
|
|
|
|
|
|
|| diag("TEST: removes all new files for \"all\" transaction"); |
1147
|
|
|
|
|
|
|
# |
1148
|
1
|
|
|
|
|
449
|
output(); |
1149
|
|
|
|
|
|
|
|
1150
|
1
|
|
|
|
|
155
|
=cut |
1151
|
1
|
|
|
|
|
1390
|
|
1152
|
|
|
|
|
|
|
#==================================================================== |
1153
|
|
|
|
|
|
|
sub undo_file ; |
1154
|
1
|
|
|
|
|
6
|
sub delete_file ; |
1155
|
1
|
|
|
|
|
7
|
sub undo_files{ |
1156
|
3
|
|
|
7
|
1
|
30
|
my ($names, @rest) = @_; |
1157
|
1
|
|
|
|
|
6
|
my $status = 1; |
|
3
|
|
|
|
|
33
|
|
1158
|
1
|
|
|
|
|
5
|
|
1159
|
1
|
|
|
|
|
3
|
#tag# |
1160
|
7
|
|
|
|
|
37
|
foreach my $dir ( expand_filenames($names)){ |
1161
|
7
|
100
|
|
|
|
20
|
if(! -e $dir){ |
1162
|
|
|
|
|
|
|
# if dir (ie tx) to undo isnt an absolute dir, assume relative to save_dir |
1163
|
7
|
|
|
|
|
51
|
$dir = "$Config{'save_dir'}/$dir"; |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
# now we need to expand again, as it may be wildcarded |
1166
|
9
|
|
|
|
|
270
|
foreach my $d ( expand_filenames($dir)){ |
1167
|
7
|
50
|
|
|
|
105
|
if(! -e $d){ |
1168
|
9
|
|
|
|
|
102
|
carp "undo_files: dir doesnt exist: $d."; |
1169
|
9
|
|
|
|
|
822
|
$status = 0; |
1170
|
0
|
|
|
|
|
0
|
next; |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
#TODO# maybe dont need this restriction, makes it safer though... |
1173
|
|
|
|
|
|
|
#restrict to existing archive dirs (transactions) |
1174
|
0
|
50
|
|
|
|
0
|
if( $d !~ m|$Config{'save_dir'}/([^/]*)| ){ |
1175
|
0
|
|
|
|
|
0
|
carp "undo_files: dir isnt an archive dir: $d."; |
1176
|
9
|
|
|
|
|
546
|
$status = 0; |
1177
|
0
|
|
|
|
|
0
|
next; |
1178
|
|
|
|
|
|
|
} |
1179
|
|
|
|
|
|
|
#print "\nRestoring files from archive dir: $d \n\t"; |
1180
|
0
|
50
|
|
|
|
0
|
find(\&undo_file, "$d") || ($status = 0); |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
#print "\nDeleting files that didnt exist before: $d \n\t"; |
1183
|
|
|
|
|
|
|
#dir undoing may be a subtree of a transaction's archive dir |
1184
|
|
|
|
|
|
|
#so get the corresponding subtree of archive.new dir |
1185
|
0
|
|
|
|
|
0
|
my $d_new = $d ; |
1186
|
9
|
|
|
|
|
2146
|
$d_new =~ s|($Config{'save_dir'}/[^/]*)|$1.new| ; |
1187
|
9
|
100
|
|
|
|
40
|
if( -e $d_new){ |
1188
|
9
|
50
|
|
|
|
411
|
find(\&delete_file, $d_new) || ($status = 0); |
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
} |
1191
|
|
|
|
|
|
|
} |
1192
|
9
|
|
|
|
|
318
|
return $status; |
1193
|
|
|
|
|
|
|
} |
1194
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
#==================================================================== |
1196
|
|
|
|
|
|
|
sub undo_file { |
1197
|
3
|
|
|
80
|
0
|
260
|
my $file = $File::Find::name ; |
1198
|
7
|
|
|
|
|
92
|
my ($dest, @rest) = ($file =~ m|$Config{'save_dir'}/[^/]*(.*)| ); |
1199
|
|
|
|
|
|
|
|
1200
|
80
|
50
|
|
|
|
124
|
if($file =~ /\.AT_\d+:\d+:\d+$/ ){ #suffix set in save_file2 |
1201
|
80
|
|
|
|
|
822
|
return 1; # not restoring non-original saves |
1202
|
|
|
|
|
|
|
} |
1203
|
80
|
100
|
|
|
|
288
|
if(! -f $file ){return 1} |
|
0
|
|
|
|
|
0
|
|
1204
|
80
|
|
|
|
|
2601
|
copy($file, $dest); #TODO# too silent on errors, however justified |
1205
|
57
|
|
|
|
|
6279
|
return 1; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
#==================================================================== |
1209
|
|
|
|
|
|
|
sub delete_file { |
1210
|
1
|
|
|
19
|
0
|
5
|
my $archive_filename = $File::Find::name ; |
|
23
|
|
|
|
|
271
|
|
1211
|
23
|
|
|
|
|
11872
|
my ($real_filename, @rest) = |
1212
|
|
|
|
|
|
|
($archive_filename =~ m|$Config{'save_dir'}/[^/]*(.*)| ); |
1213
|
1
|
|
|
|
|
318
|
|
|
1
|
|
|
|
|
16
|
|
1214
|
1
|
100
|
|
|
|
730
|
if(! -f $archive_filename ){return 1} |
|
19
|
|
|
|
|
35
|
|
|
19
|
|
|
|
|
182
|
|
1215
|
19
|
|
|
|
|
670
|
my $rc = unlink($real_filename); |
1216
|
|
|
|
|
|
|
#silent, as may fail unlink as may already have been deleted |
1217
|
|
|
|
|
|
|
#when undid a transaction, so cant unlink again when do undo all |
1218
|
|
|
|
|
|
|
#unless($rc){carp "delete_file: unlink: $!";} |
1219
|
15
|
|
|
|
|
1312
|
return 1; |
1220
|
|
|
|
|
|
|
} |
1221
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
#==================================================================== |
1223
|
|
|
|
|
|
|
# check_pkg |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
=begin testing |
1226
|
|
|
|
|
|
|
|
1227
|
1
|
|
|
|
|
6
|
test_reset(); |
1228
|
1
|
|
|
|
|
8
|
system('rpm -e perl-NCustomDummy > /dev/null 2>&1'); |
1229
|
|
|
|
|
|
|
|
1230
|
1
|
|
|
|
|
9
|
my $junk = "JUNK gg"; |
1231
|
1
|
50
|
|
|
|
12121
|
ok(! &NCustom::check_pkg($junk)) |
1232
|
|
|
|
|
|
|
|| diag("TEST: checks input format"); |
1233
|
|
|
|
|
|
|
# supress expected error message: |
1234
|
1
|
|
|
|
|
30
|
$_STDERR_ =~ s/check_pkg: invalid arguments. at lib\/NCustom.pm line \d+\n// ; |
1235
|
|
|
|
|
|
|
# |
1236
|
1
|
|
|
|
|
49
|
my $req = { match => "", version => "0.0.0", pkg => "", result => ""}; |
1237
|
1
|
|
|
|
|
582
|
my $p = "perl-NCustomDummy"; |
1238
|
|
|
|
|
|
|
# |
1239
|
1
|
|
|
|
|
23
|
$req = { match => "MINIMUM", version => "0.0.0", pkg => $p, result=>"" }; |
1240
|
1
|
50
|
|
|
|
3
|
&NCustom::check_pkg($req); is($$req{'result'}, "MISSING") |
|
1
|
|
|
|
|
5
|
|
1241
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets minimum version 1/4"); |
1242
|
1
|
|
|
|
|
10
|
$req = { match => "MAXIMUM", version => "0.0.0", pkg => $p, result=>"" }; |
1243
|
1
|
50
|
|
|
|
27
|
&NCustom::check_pkg($req); is($$req{'result'}, "MISSING") |
|
1
|
|
|
|
|
630
|
|
1244
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets maximum version 1/4"); |
1245
|
1
|
|
|
|
|
13
|
$req = { match => "EXACTLY", version => "0.0.0", pkg => $p, result=>"" }; |
1246
|
1
|
50
|
|
|
|
40
|
&NCustom::check_pkg($req); is($$req{'result'}, "MISSING") |
|
1
|
|
|
|
|
525
|
|
1247
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets exact version 1/4"); |
1248
|
1
|
|
|
|
|
23
|
$req = { match => "NOTWANT", version => "0.0.0", pkg => $p, result=>"" }; |
1249
|
1
|
50
|
|
|
|
39
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
526
|
|
1250
|
|
|
|
|
|
|
|| diag("TEST: checks if package present 1/4"); |
1251
|
|
|
|
|
|
|
# |
1252
|
1
|
|
|
|
|
23
|
system("rpm -i $input/perl-NCustomDummy-1.23-1.noarch.rpm"); |
1253
|
|
|
|
|
|
|
#shouldnt assume this works |
1254
|
|
|
|
|
|
|
# |
1255
|
1
|
|
|
|
|
28
|
$req = { match => "MINIMUM", version => "1.09.1", pkg => $p, result=>"" }; |
1256
|
1
|
50
|
|
|
|
5956
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
89
|
|
1257
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets minimum version 2/4"); |
1258
|
1
|
|
|
|
|
55
|
$req = { match => "MINIMUM", version => "1.23", pkg => $p, result=>"" }; |
1259
|
1
|
50
|
|
|
|
65
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
1301
|
|
1260
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets minimum version 3/4"); |
1261
|
1
|
|
|
|
|
19
|
$req = { match => "MINIMUM", version => "1.99.9", pkg => $p, result=>"" }; |
1262
|
1
|
50
|
|
|
|
51
|
&NCustom::check_pkg($req); is($$req{'result'}, "BELOW") |
|
1
|
|
|
|
|
1762
|
|
1263
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets minimum version 4/4"); |
1264
|
|
|
|
|
|
|
# |
1265
|
1
|
|
|
|
|
12
|
$req = { match => "MAXIMUM", version => "1.09.1", pkg => $p, result=>"" }; |
1266
|
1
|
50
|
|
|
|
50
|
&NCustom::check_pkg($req); is($$req{'result'}, "ABOVE") |
|
1
|
|
|
|
|
1772
|
|
1267
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets maximum version 2/4"); |
1268
|
1
|
|
|
|
|
16
|
$req = { match => "MAXIMUM", version => "1.23", pkg => $p, result=>"" }; |
1269
|
1
|
50
|
|
|
|
45
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
1848
|
|
1270
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets maximum version 3/4"); |
1271
|
1
|
|
|
|
|
14
|
$req = { match => "MAXIMUM", version => "1.99.9", pkg => $p, result=>"" }; |
1272
|
1
|
50
|
|
|
|
51
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
1735
|
|
1273
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets maximum version 4/4"); |
1274
|
|
|
|
|
|
|
# |
1275
|
1
|
|
|
|
|
21
|
$req = { match => "EXACTLY", version => "1.09.1", pkg => $p, result=>"" }; |
1276
|
1
|
50
|
|
|
|
35
|
&NCustom::check_pkg($req); is($$req{'result'}, "ABOVE") |
|
1
|
|
|
|
|
1693
|
|
1277
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets exact version 2/4"); |
1278
|
1
|
|
|
|
|
18
|
$req = { match => "EXACTLY", version => "1.23", pkg => $p, result=>"" }; |
1279
|
1
|
50
|
|
|
|
34
|
&NCustom::check_pkg($req); is($$req{'result'}, "OK") |
|
1
|
|
|
|
|
1622
|
|
1280
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets exact version 3/4"); |
1281
|
1
|
|
|
|
|
20
|
$req = { match => "EXACTLY", version => "1.99.9", pkg => $p, result=>"" }; |
1282
|
1
|
50
|
|
|
|
39
|
&NCustom::check_pkg($req); is($$req{'result'}, "BELOW") |
|
1
|
|
|
|
|
1624
|
|
1283
|
|
|
|
|
|
|
|| diag("TEST: checks if package meets exact version 4/4"); |
1284
|
|
|
|
|
|
|
# |
1285
|
1
|
|
|
|
|
15
|
$req = { match => "NOTWANT", version => "1.09.1", pkg => $p, result=>"" }; |
1286
|
1
|
50
|
|
|
|
43
|
&NCustom::check_pkg($req); is($$req{'result'}, "UNWELCOME") |
|
1
|
|
|
|
|
1760
|
|
1287
|
|
|
|
|
|
|
|| diag("TEST: checks if package present 2/4"); |
1288
|
1
|
|
|
|
|
15
|
$req = { match => "NOTWANT", version => "1.23", pkg => $p, result=>"" }; |
1289
|
1
|
50
|
|
|
|
35
|
&NCustom::check_pkg($req); is($$req{'result'}, "UNWELCOME") |
|
1
|
|
|
|
|
1589
|
|
1290
|
|
|
|
|
|
|
|| diag("TEST: checks if package present 3/4"); |
1291
|
1
|
|
|
|
|
20
|
$req = { match => "NOTWANT", version => "1.99.9", pkg => $p, result=>"" }; |
1292
|
1
|
50
|
|
|
|
39
|
&NCustom::check_pkg($req); is($$req{'result'}, "UNWELCOME") |
|
1
|
|
|
|
|
1456
|
|
1293
|
|
|
|
|
|
|
|| diag("TEST: checks if package present 4/4"); |
1294
|
|
|
|
|
|
|
# |
1295
|
1
|
|
|
|
|
15
|
output(); |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
=end testing |
1298
|
1
|
|
|
|
|
33
|
|
1299
|
1
|
|
|
|
|
1622
|
=cut |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
#==================================================================== |
1302
|
|
|
|
|
|
|
sub vcmp ; |
1303
|
1
|
|
|
|
|
167
|
sub check_pkg { |
|
1
|
|
|
|
|
26
|
|
1304
|
1
|
|
|
21
|
0
|
9
|
my ($req, @rest) = @_ ; |
|
4
|
|
|
|
|
348
|
|
1305
|
|
|
|
|
|
|
#$req = { match => "", version => "", pkg => "", result => ""}; |
1306
|
|
|
|
|
|
|
|
1307
|
4
|
100
|
|
|
|
90
|
if(! defined $$req{'match'}){ |
1308
|
21
|
|
|
|
|
81
|
carp "check_pkg: invalid arguments."; |
1309
|
21
|
|
|
|
|
235
|
return 0 ; |
1310
|
|
|
|
|
|
|
} |
1311
|
1
|
50
|
|
|
|
449
|
if($$req{'match'} !~ /(MINIMUM)|(MAXIMUM)|(EXACTLY)|(NOTWANT)/){ |
1312
|
1
|
|
|
|
|
29
|
carp "check_pkg: invalid argument values."; |
1313
|
20
|
|
|
|
|
295
|
return 0 ; |
1314
|
|
|
|
|
|
|
} |
1315
|
|
|
|
|
|
|
|
1316
|
0
|
|
|
|
|
0
|
my $rc = system("rpm -q $$req{'pkg'}"); |
1317
|
|
|
|
|
|
|
|
1318
|
0
|
50
|
33
|
|
|
0
|
if(($rc == 0)and($$req{'match'} =~ /NOTWANT/)){ |
1319
|
20
|
|
|
|
|
106652
|
$$req{'result'} = "UNWELCOME"; |
1320
|
20
|
|
|
|
|
422
|
return 1; |
1321
|
|
|
|
|
|
|
} |
1322
|
0
|
100
|
66
|
|
|
0
|
if(($rc != 0)and($$req{'match'} =~ /NOTWANT/)){ |
1323
|
0
|
|
|
|
|
0
|
$$req{'result'} = "OK"; |
1324
|
20
|
|
|
|
|
896
|
return 1; |
1325
|
|
|
|
|
|
|
} |
1326
|
6
|
50
|
33
|
|
|
78
|
if(($rc != 0)and($$req{'match'} !~ /NOTWANT/)){ |
1327
|
6
|
|
|
|
|
144
|
$$req{'result'} = "MISSING"; |
1328
|
14
|
|
|
|
|
349
|
return 1; |
1329
|
|
|
|
|
|
|
} |
1330
|
|
|
|
|
|
|
|
1331
|
14
|
|
|
|
|
135
|
my $ver = `rpm -q $$req{'pkg'} --qf \%{VERSION}` . ""; |
1332
|
14
|
|
|
|
|
372
|
my $reqver = "$$req{'version'}" . ""; |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
# vstring will be deprecated, by then we'll find a module for it |
1335
|
0
|
0
|
0
|
|
|
0
|
if(($$req{'match'} =~ /EXACTLY/) and(vcmp($ver, "eq", $reqver))){ |
1336
|
0
|
|
|
|
|
0
|
$$req{'result'} = "OK"; |
1337
|
0
|
|
|
|
|
0
|
return 1; |
1338
|
|
|
|
|
|
|
} |
1339
|
0
|
0
|
0
|
|
|
0
|
if(($$req{'match'} =~ /MINIMUM|EXACTLY/) and(vcmp($ver, "lt", $reqver))){ |
1340
|
0
|
|
|
|
|
0
|
$$req{'result'} = "BELOW"; |
1341
|
0
|
|
|
|
|
0
|
return 1; |
1342
|
|
|
|
|
|
|
} |
1343
|
0
|
0
|
0
|
|
|
0
|
if(($$req{'match'} =~ /MAXIMUM|EXACTLY/) and(vcmp($ver, "gt", $reqver))){ |
1344
|
0
|
|
|
|
|
0
|
$$req{'result'} = "ABOVE"; |
1345
|
0
|
|
|
|
|
0
|
return 1; |
1346
|
|
|
|
|
|
|
} |
1347
|
|
|
|
|
|
|
# fall-through is brave ? check this logic |
1348
|
0
|
|
|
|
|
0
|
$$req{'result'} = "OK"; |
1349
|
0
|
|
|
|
|
0
|
return 1; |
1350
|
|
|
|
|
|
|
} |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
#==================================================================== |
1353
|
|
|
|
|
|
|
# required_packages |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
=item C |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=begin example |
1358
|
|
|
|
|
|
|
|
1359
|
1
|
|
|
|
|
3
|
test_reset(); |
1360
|
1
|
50
|
|
|
|
2
|
can_ok("NCustom", qw(required_packages)) |
1361
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1362
|
|
|
|
|
|
|
#that was test 93 |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
=end example |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
=for example begin |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
sub handler{ |
1369
|
0
|
|
|
0
|
|
0
|
my ($reqref, $url, $file) = @_; |
|
0
|
|
|
1
|
|
0
|
|
1370
|
0
|
|
|
|
|
0
|
print "As $$reqref{'match'} version $$reqref{'version'} of "; |
|
0
|
|
|
|
|
0
|
|
1371
|
0
|
|
|
|
|
0
|
print "$$reqref{'pkg'} was $$reqref{'result'} - "; |
|
1
|
|
|
|
|
6
|
|
1372
|
0
|
|
|
|
|
0
|
print "we are going to fetch $file from $url and execute it.\n"; |
|
1
|
|
|
|
|
38
|
|
1373
|
0
|
|
|
|
|
0
|
print "This should set things right.\n"; |
|
1
|
|
|
|
|
31
|
|
1374
|
0
|
|
|
|
|
0
|
return 1; |
|
1
|
|
|
|
|
16
|
|
1375
|
|
|
|
|
|
|
} |
1376
|
|
|
|
|
|
|
|
1377
|
1
|
|
|
|
|
9
|
required_packages(<<' EOF'); |
1378
|
|
|
|
|
|
|
EXACTLY; 9.9.9; acme; handler($req, "URL", "FILE") |
1379
|
|
|
|
|
|
|
NOTWANT; 0.0.0; perl; print "Dont be stupid\n" |
1380
|
|
|
|
|
|
|
#MAXIMUM; 9.9.9; perl; carp("Warning: untested with this perl") |
1381
|
|
|
|
|
|
|
#MINIMUM; 9.9.9; perl; apt_fix() |
1382
|
|
|
|
|
|
|
NOTWANT; 0.0.0; perl; for($i = 0; $i < 10; $i++){$s="Hello"; print "${s}${i}\n"} |
1383
|
|
|
|
|
|
|
EOF |
1384
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
=for example end |
1386
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
Required packages take a multi-line argument list, where each line is of the format: requirement, version, package, handler code. |
1388
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
Required packages will invoke the handler if the package is (or isnt) installed as per the requirement and version. |
1390
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
Valid requirements are: MINUMUM, MAXUMUM, EXACTLY, and NOTWANT. |
1392
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
Input lines will be ignored if the first non-whitespace character is the '#' character. |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
The handler code is eval'd, and it may make use of the hashref "req". The hash has the keys: match, version, and package; which correspond to the original arguments. The hash also contains result, which is the answer as to whether the requirements was met or not. Possible values of result (each referring to the package or it's version in relation to the requuirements) are: MISSING, ABOVE, BELOW, or UNWELCOME. |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
A handler "apt_fix" is provided that will simply attempt to remove UNWELCOME packages, and do an install for all other scenarios - so you might get the verion you want or not, depending upon your apt repository. |
1398
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
=for example_testing |
1400
|
1
|
|
|
|
|
77
|
my $o = $_STDOUT_; |
1401
|
1
|
|
|
|
|
1769
|
my $e = $_STDERR_; |
1402
|
1
|
50
|
|
|
|
7
|
like($o, qr/As EXACTLY version .* fetch FILE from URL and execute it.\n/) |
1403
|
|
|
|
|
|
|
|| diag("TEST: calls a handler"); |
1404
|
1
|
50
|
|
|
|
4
|
like($o, qr/Dont be stupid/) |
1405
|
|
|
|
|
|
|
|| diag("TEST: executes simple statements"); |
1406
|
1
|
50
|
|
|
|
39
|
like($o, qr/Hello9/) |
1407
|
|
|
|
|
|
|
|| diag("TEST: executes compound statements"); |
1408
|
|
|
|
|
|
|
# |
1409
|
|
|
|
|
|
|
# supress expected output |
1410
|
1
|
|
|
|
|
729
|
$_STDOUT_ =~ s/Hello\d+\n//gm ; |
1411
|
1
|
|
|
|
|
12125
|
$_STDOUT_ =~ s/Dont be stupid\n//gm ; |
1412
|
1
|
|
|
|
|
1138
|
$_STDOUT_ =~ s/As EXACTLY version .* fetch FILE from URL and execute it.\n//gm ; |
1413
|
1
|
|
|
|
|
7
|
$_STDOUT_ =~ s/This should set things right.\n//gm ; |
1414
|
|
|
|
|
|
|
# |
1415
|
1
|
|
|
|
|
16
|
output(); |
1416
|
|
|
|
|
|
|
|
1417
|
1
|
|
|
|
|
11
|
|
1418
|
1
|
|
|
|
|
17
|
=cut |
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
#==================================================================== |
1421
|
1
|
|
|
|
|
2
|
sub required_packages { |
1422
|
1
|
|
|
1
|
1
|
7
|
my ($requirements, @rest) = @_; |
|
1
|
|
|
|
|
13
|
|
1423
|
1
|
|
|
|
|
30
|
my $status = 1; |
1424
|
1
|
|
|
|
|
4
|
my $rc = 1; |
|
1
|
|
|
|
|
14
|
|
1425
|
1
|
|
|
|
|
6
|
|
1426
|
1
|
|
|
|
|
2
|
my @lines = split(/\n/,$requirements); |
|
1
|
|
|
|
|
8
|
|
1427
|
1
|
|
|
|
|
12
|
foreach my $line (@lines){ |
1428
|
1
|
|
|
|
|
23
|
$line =~ s/^\s+//; #trim leading whitespace |
1429
|
1
|
100
|
|
|
|
14
|
next if $line =~ /^#/; #TODO# comments need much work |
1430
|
|
|
|
|
|
|
|
1431
|
5
|
|
|
|
|
117
|
$req = { match => "", version => "0.0.0", pkg => "", result => ""}; |
1432
|
5
|
|
|
|
|
35
|
($$req{'match'}, $$req{'version'}, $$req{'pkg'}, my @rest) |
1433
|
|
|
|
|
|
|
= parse_line('\s*;\s*',1, $line); |
1434
|
3
|
|
|
|
|
76
|
my $code = join(';',@rest); |
1435
|
|
|
|
|
|
|
|
1436
|
3
|
|
|
|
|
91
|
$rc = check_pkg($req); |
1437
|
3
|
50
|
|
|
|
2983
|
unless($rc){$status = 0; next} |
|
3
|
|
|
|
|
72
|
|
|
3
|
|
|
|
|
47
|
|
1438
|
|
|
|
|
|
|
|
1439
|
0
|
100
|
|
|
|
0
|
if($$req{'result'} ne "OK"){ |
1440
|
|
|
|
|
|
|
#we invoke handler from caller's perspective |
1441
|
|
|
|
|
|
|
package main ; |
1442
|
2
|
|
|
2
|
|
3
|
no strict; no warnings; |
|
2
|
|
|
2
|
|
3980
|
|
|
2
|
|
|
|
|
22
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
69
|
|
|
2
|
|
|
|
|
13
|
|
1443
|
0
|
|
|
|
|
0
|
eval $code ; |
1444
|
3
|
50
|
|
|
|
76
|
if($@){ |
1445
|
1
|
|
|
|
|
365
|
carp("required_packages: code \n$code \nraised the error $@"); |
1446
|
1
|
|
|
|
|
15
|
$NCustom::status = 0; |
1447
|
|
|
|
|
|
|
} |
1448
|
2
|
|
|
2
|
|
5
|
use strict; use warnings; |
|
2
|
|
|
2
|
|
158
|
|
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
67
|
|
|
2
|
|
|
|
|
10
|
|
1449
|
|
|
|
|
|
|
# |
1450
|
|
|
|
|
|
|
#back to normal |
1451
|
|
|
|
|
|
|
package NCustom ; |
1452
|
1
|
|
|
|
|
3
|
$rc = check_pkg($req); |
|
0
|
|
|
|
|
0
|
|
1453
|
0
|
50
|
33
|
|
|
0
|
unless(($$req{'result'} eq "OK") && ($rc)){ $status = 0; } |
|
1
|
|
|
|
|
11
|
|
1454
|
|
|
|
|
|
|
} |
1455
|
1
|
|
|
|
|
153
|
} |
|
1
|
|
|
|
|
21
|
|
1456
|
1
|
|
|
|
|
255
|
return $status; |
|
1
|
|
|
|
|
43
|
|
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
#==================================================================== |
1460
|
|
|
|
|
|
|
# apt_fix |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
=begin testing |
1463
|
|
|
|
|
|
|
|
1464
|
1
|
|
|
|
|
6
|
test_reset(); |
1465
|
1
|
50
|
33
|
|
|
11
|
SKIP: { |
1466
|
1
|
|
|
|
|
8
|
skip "apt too intrusive", 6 unless (defined $ENV{'TEST_APT'} || defined $ENV{'TEST_ALL'}); |
1467
|
|
|
|
|
|
|
############# |
1468
|
1
|
|
|
|
|
37
|
system('rpm -e perl-NCustomDummy > /dev/null 2>&1'); |
1469
|
1
|
|
|
|
|
97
|
my ($version, $rc); |
1470
|
0
|
|
|
|
|
0
|
$version = `rpm -q perl-NCustomDummy --qf \%{VERSION}`; |
1471
|
0
|
0
|
|
|
|
0
|
like($version, qr/package perl-NCustomDummy is not installed/) |
1472
|
|
|
|
|
|
|
|| diag("TEST: must remove perl-NCustomDummy package"); |
1473
|
|
|
|
|
|
|
# |
1474
|
|
|
|
|
|
|
# |
1475
|
0
|
0
|
|
|
|
0
|
can_ok("NCustom", qw(apt_fix)) |
1476
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1477
|
|
|
|
|
|
|
# |
1478
|
0
|
|
|
|
|
0
|
$rc = required_packages(<<' EOF'); |
1479
|
|
|
|
|
|
|
EXACTLY; 9.9.9; perl-NCustomDummy; apt_fix() |
1480
|
|
|
|
|
|
|
EOF |
1481
|
0
|
0
|
|
|
|
0
|
ok(! $rc) |
1482
|
|
|
|
|
|
|
|| diag("TEST: must return 0 if requirements arent met"); |
1483
|
0
|
|
|
|
|
0
|
$version = `rpm -q perl-NCustomDummy --qf \%{VERSION}`; |
1484
|
0
|
0
|
|
|
|
0
|
like($version, qr/1.23/) |
1485
|
|
|
|
|
|
|
|| diag("TEST: must will install its version rather than nothing"); |
1486
|
|
|
|
|
|
|
# |
1487
|
0
|
|
|
|
|
0
|
$rc = required_packages(<<' EOF'); |
1488
|
|
|
|
|
|
|
NOTWANT; 9.9.9; perl-NCustomDummy; apt_fix() |
1489
|
|
|
|
|
|
|
EOF |
1490
|
0
|
0
|
|
|
|
0
|
is($rc, 1) |
1491
|
|
|
|
|
|
|
|| diag("TEST: must return 1 if requirements are met"); |
1492
|
0
|
|
|
|
|
0
|
$version = `rpm -q perl-NCustomDummy --qf \%{VERSION}`; |
1493
|
0
|
0
|
|
|
|
0
|
like($version, qr/package perl-NCustomDummy is not installed/) |
1494
|
|
|
|
|
|
|
|| diag("TEST: will remove unwanted packages"); |
1495
|
|
|
|
|
|
|
############ |
1496
|
|
|
|
|
|
|
} |
1497
|
0
|
|
|
|
|
0
|
output(); |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
=end testing |
1500
|
0
|
|
|
|
|
0
|
|
1501
|
1
|
|
|
|
|
3971
|
=cut |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
#==================================================================== |
1504
|
|
|
|
|
|
|
sub apt_fix { |
1505
|
1
|
0
|
|
0
|
0
|
337
|
if($$req{'result'} =~ /UNWELCOME/){ |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
22
|
|
1506
|
1
|
|
|
|
|
6
|
system("apt-get -q -y remove $$req{'pkg'}"); |
|
1
|
|
|
|
|
34
|
|
1507
|
|
|
|
|
|
|
}else{ |
1508
|
0
|
|
|
|
|
0
|
system("apt-get -q -y install $$req{'pkg'}"); |
1509
|
|
|
|
|
|
|
} |
1510
|
0
|
|
|
|
|
0
|
return 1; #hmm |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
#==================================================================== |
1514
|
|
|
|
|
|
|
# vcmp |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
=begin testing |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
#FALSE |
1519
|
1
|
50
|
|
|
|
2
|
ok(! &NCustom::vcmp(1,"gt",2) ) |
1520
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1521
|
1
|
50
|
|
|
|
5
|
ok(! &NCustom::vcmp(1,"eq",2) ) |
1522
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1523
|
1
|
50
|
|
|
|
23
|
ok(! &NCustom::vcmp(3,"gt",3) ) |
1524
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1525
|
1
|
50
|
|
|
|
1421
|
ok(! &NCustom::vcmp(3,"lt",3) ) |
1526
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1527
|
1
|
50
|
|
|
|
684
|
ok(! &NCustom::vcmp(3,"ne",3) ) |
1528
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1529
|
|
|
|
|
|
|
# |
1530
|
|
|
|
|
|
|
#TRUE"; |
1531
|
1
|
50
|
|
|
|
748
|
ok(&NCustom::vcmp(1,"lt",2) ) |
1532
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1533
|
1
|
50
|
|
|
|
848
|
ok(&NCustom::vcmp(1,"ne",2) ) |
1534
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1535
|
1
|
50
|
|
|
|
542
|
ok(&NCustom::vcmp(3,"eq",3) ) |
1536
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1537
|
1
|
50
|
|
|
|
818
|
ok(&NCustom::vcmp("1.2.3","lt",2) ) |
1538
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1539
|
1
|
50
|
|
|
|
749
|
ok(&NCustom::vcmp("1.2.3","gt","1.1.99") ) |
1540
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1541
|
1
|
50
|
|
|
|
673
|
ok(&NCustom::vcmp("1.2.3","eq","1.2.3") ) |
1542
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1543
|
1
|
50
|
|
|
|
767
|
ok(&NCustom::vcmp(1,"ne",0) ) |
1544
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1545
|
1
|
50
|
|
|
|
566
|
ok(&NCustom::vcmp("1.2.3","lt",2) ) |
1546
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1547
|
1
|
50
|
|
|
|
725
|
ok(&NCustom::vcmp("1.2.3","gt","1.1.99") ) |
1548
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1549
|
1
|
50
|
|
|
|
606
|
ok(&NCustom::vcmp("1.2.3","eq","1.2.3") ) |
1550
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1551
|
1
|
50
|
|
|
|
911
|
ok(&NCustom::vcmp(1,"ne",0) ) |
1552
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1553
|
1
|
50
|
|
|
|
1002
|
ok(&NCustom::vcmp("1.2.3","lt","1.03") ) |
1554
|
|
|
|
|
|
|
|| diag("TEST: compares version strings"); |
1555
|
1
|
|
|
|
|
637
|
output(); |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
=end testing |
1558
|
1
|
|
|
|
|
670
|
|
1559
|
1
|
|
|
|
|
1669
|
=cut |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
|
1562
|
1
|
|
|
|
|
2
|
#==================================================================== |
1563
|
1
|
|
|
|
|
3
|
sub vcmp { |
1564
|
1
|
|
|
30
|
0
|
3
|
my ($vstring1, $cmp, $vstring2) = @_; |
|
0
|
|
|
|
|
0
|
|
1565
|
0
|
|
|
|
|
0
|
my ($v1, $v2, $dummy, @rest); |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
# check input ###################################### |
1568
|
30
|
50
|
|
|
|
310
|
if( $cmp !~ /(lt)|(gt)|(eq)|(ne)/ ){ |
1569
|
30
|
|
|
|
|
40
|
carp "vcmp: invalid comparision operator: $cmp.\n"; |
1570
|
30
|
|
|
|
|
124
|
return 0; #arbitrary |
1571
|
|
|
|
|
|
|
} |
1572
|
0
|
50
|
|
|
|
0
|
if( $vstring1 !~ /^(\d+\.)*\d*$/ ){ |
1573
|
0
|
|
|
|
|
0
|
carp "vcmp: invalid version string: $vstring1.\n"; |
1574
|
30
|
|
|
|
|
145
|
return 0; #arbitrary |
1575
|
|
|
|
|
|
|
} |
1576
|
0
|
50
|
|
|
|
0
|
if( $vstring2 !~ /^(\d+\.)*\d*$/ ){ |
1577
|
0
|
|
|
|
|
0
|
carp "vcmp: invalid version string: $vstring2.\n"; |
1578
|
30
|
|
|
|
|
112
|
return 0; #arbitrary |
1579
|
|
|
|
|
|
|
} |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
# reduce ########################################### |
1582
|
0
|
|
|
|
|
0
|
$vstring1 =~ s/^\.*([^\.]+)\.*// ; |
1583
|
0
|
|
|
|
|
0
|
$v1 = $1; |
1584
|
|
|
|
|
|
|
#if($v1 eq ""){$v1 = 0} |
1585
|
|
|
|
|
|
|
#if($vstring1 eq ""){$vstring1 = 0} |
1586
|
|
|
|
|
|
|
#print "\n\t\tv1: $v1 vstring1: $vstring1 "; |
1587
|
|
|
|
|
|
|
# |
1588
|
30
|
|
|
|
|
115
|
$vstring2 =~ s/^\.*([^\.]+)\.*// ; |
1589
|
30
|
|
|
|
|
65
|
$v2 = $1; |
1590
|
|
|
|
|
|
|
#if($v2 eq ""){$v2 = 0} |
1591
|
|
|
|
|
|
|
#if($vstring2 eq ""){$vstring2 = 0} |
1592
|
|
|
|
|
|
|
#print "\n\t\tv2: $v2 vstring2: $vstring2 "; |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
# result/recuse ################################### |
1596
|
30
|
100
|
|
|
|
180
|
if( $cmp eq "eq"){ |
1597
|
30
|
100
|
66
|
|
|
153
|
if((! defined $v1) and (! defined $v2)){ |
|
|
50
|
33
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1598
|
1
|
|
|
|
|
2
|
return 1; |
|
30
|
|
|
|
|
78
|
|
1599
|
|
|
|
|
|
|
}elsif((! defined $v1) or (! defined $v2)){ |
1600
|
11
|
|
|
|
|
90
|
return 0; |
1601
|
1
|
|
|
|
|
308
|
}elsif( $v1 != $v2 ){ |
|
1
|
|
|
|
|
21
|
|
1602
|
1
|
|
|
|
|
521
|
return 0; |
|
3
|
|
|
|
|
20
|
|
1603
|
|
|
|
|
|
|
}elsif( $v1 != $v2 ){ |
1604
|
|
|
|
|
|
|
}else{ |
1605
|
0
|
|
|
|
|
0
|
return vcmp($vstring1, $cmp, $vstring2) ; |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
} |
1608
|
1
|
100
|
|
|
|
7
|
if( $cmp eq "ne"){ |
1609
|
7
|
100
|
66
|
|
|
26
|
if((! defined $v1) and (! defined $v2)){ |
|
|
50
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1610
|
19
|
|
|
|
|
43
|
return 0; |
1611
|
|
|
|
|
|
|
}elsif((! defined $v1) or (! defined $v2)){ |
1612
|
5
|
|
|
|
|
55
|
return 1; |
1613
|
|
|
|
|
|
|
}elsif( $v1 != $v2 ){ |
1614
|
1
|
|
|
|
|
5
|
return 1; |
1615
|
|
|
|
|
|
|
}elsif($v1 eq "" && $v2 eq ""){ |
1616
|
0
|
|
|
|
|
0
|
return 0; |
1617
|
|
|
|
|
|
|
}else{ |
1618
|
3
|
|
|
|
|
16
|
return vcmp($vstring1, $cmp, $vstring2) ; |
1619
|
|
|
|
|
|
|
} |
1620
|
|
|
|
|
|
|
} |
1621
|
0
|
100
|
|
|
|
0
|
if( $cmp eq "lt"){ |
1622
|
1
|
100
|
66
|
|
|
3
|
if((! defined $v1) and (! defined $v2)){ |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1623
|
14
|
|
|
|
|
38
|
return 0; |
1624
|
|
|
|
|
|
|
}elsif((! defined $v1) and ( defined $v2)){ |
1625
|
7
|
|
|
|
|
87
|
return 1; |
1626
|
|
|
|
|
|
|
}elsif(( defined $v1) and (!defined $v2)){ |
1627
|
1
|
|
|
|
|
6
|
return 0; |
1628
|
|
|
|
|
|
|
}elsif( $v1 < $v2 ){ |
1629
|
0
|
|
|
|
|
0
|
return 1; |
1630
|
|
|
|
|
|
|
}elsif($v1 > $v2 ){ |
1631
|
0
|
|
|
|
|
0
|
return 0; |
1632
|
|
|
|
|
|
|
}elsif($v1 eq "" && $v2 eq ""){ |
1633
|
4
|
|
|
|
|
20
|
return 0; |
1634
|
|
|
|
|
|
|
}else{ |
1635
|
0
|
|
|
|
|
0
|
return vcmp($vstring1, $cmp, $vstring2) ; |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
} |
1638
|
0
|
50
|
|
|
|
0
|
if( $cmp eq "gt"){ |
1639
|
2
|
100
|
66
|
|
|
10
|
if((! defined $v1) and (! defined $v2)){ |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1640
|
7
|
|
|
|
|
50
|
return 0; |
1641
|
|
|
|
|
|
|
}elsif((! defined $v1) and ( defined $v2)){ |
1642
|
7
|
|
|
|
|
99
|
return 0; |
1643
|
|
|
|
|
|
|
}elsif(( defined $v1) and (!defined $v2)){ |
1644
|
1
|
|
|
|
|
6
|
return 1; |
1645
|
|
|
|
|
|
|
}elsif( $v1 > $v2 ){ |
1646
|
0
|
|
|
|
|
0
|
return 1; |
1647
|
|
|
|
|
|
|
}elsif($v1 < $v2 ){ |
1648
|
0
|
|
|
|
|
0
|
return 0; |
1649
|
|
|
|
|
|
|
}elsif($v1 eq "" && $v2 eq ""){ |
1650
|
|
|
|
|
|
|
#}elsif($v1 == 0 && $v2 == 0){ |
1651
|
2
|
|
|
|
|
12
|
return 0; |
1652
|
|
|
|
|
|
|
}else{ |
1653
|
1
|
|
|
|
|
15
|
return vcmp($vstring1, $cmp, $vstring2) ; |
1654
|
|
|
|
|
|
|
} |
1655
|
|
|
|
|
|
|
} |
1656
|
|
|
|
|
|
|
} |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
#==================================================================== |
1659
|
|
|
|
|
|
|
# blat_myconfig |
1660
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
=item C |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
=begin example |
1664
|
|
|
|
|
|
|
|
1665
|
1
|
|
|
|
|
5
|
test_reset(); |
1666
|
1
|
50
|
|
|
|
2
|
can_ok("NCustom", qw(blat_myconfig)) |
1667
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
=end example |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
=for example begin |
1672
|
|
|
|
|
|
|
|
1673
|
1
|
|
|
|
|
5
|
blat_myconfig(); |
1674
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
=for example end |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
Blat_myconfig overwrites the personal configuration profile with the global configuration profile. The personal configuration profile is "~/.ncustom/NCustom/MyConfig.pm". |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
=for example_testing |
1681
|
1
|
50
|
|
|
|
101
|
is(compare("$output/.ncustom/NCustom/MyConfig.pm", "$input/Global.pm"), 0) |
1682
|
|
|
|
|
|
|
|| diag(<<' EOF'); |
1683
|
|
|
|
|
|
|
TEST: |
1684
|
|
|
|
|
|
|
TEST: - MyConfig.pm replaced by Config.pm |
1685
|
|
|
|
|
|
|
TEST: - This test will fail if you change Config.pm and |
1686
|
|
|
|
|
|
|
TEST: dont update reference copies used in test comparision. |
1687
|
|
|
|
|
|
|
EOF |
1688
|
|
|
|
|
|
|
# |
1689
|
1
|
|
|
|
|
1319
|
output(); |
1690
|
|
|
|
|
|
|
|
1691
|
1
|
|
|
|
|
25
|
|
1692
|
1
|
|
|
|
|
757
|
=cut |
1693
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
#==================================================================== |
1695
|
1
|
|
|
|
|
2
|
sub blat_myconfig { |
1696
|
1
|
|
|
2
|
1
|
4
|
my $rc ; |
|
0
|
|
|
|
|
0
|
|
1697
|
3
|
|
|
|
|
20
|
my $myconfig_file_dir = "$ENV{'HOME'}/.ncustom/NCustom"; |
1698
|
1
|
|
|
|
|
1
|
my $myconfig_file = "$myconfig_file_dir/MyConfig.pm"; |
|
2
|
|
|
|
|
11
|
|
1699
|
1
|
|
|
|
|
2
|
my $global_config_file = "dummy" ; |
|
2
|
|
|
|
|
12
|
|
1700
|
1
|
|
|
|
|
3
|
|
1701
|
|
|
|
|
|
|
# ensure target directory exists |
1702
|
2
|
100
|
|
|
|
14
|
if( ! -e $myconfig_file_dir){ |
1703
|
2
|
|
|
|
|
17
|
$rc = mkpath $myconfig_file_dir; |
1704
|
2
|
50
|
|
|
|
104
|
unless($rc){ |
1705
|
1
|
|
|
|
|
471
|
carp "blat_myconfig: couldnt create $myconfig_file_dir: $!"; |
1706
|
1
|
|
|
|
|
13
|
return 0; |
1707
|
|
|
|
|
|
|
} |
1708
|
|
|
|
|
|
|
} |
1709
|
0
|
50
|
|
|
|
0
|
if( ! -d $myconfig_file_dir){ |
1710
|
0
|
|
|
|
|
0
|
carp "blat_myconfig: not at directory: $myconfig_file_dir"; |
1711
|
2
|
|
|
|
|
55
|
return 0; |
1712
|
|
|
|
|
|
|
} |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
# find source file |
1715
|
0
|
|
|
|
|
0
|
foreach my $i (@INC){ |
1716
|
0
|
100
|
|
|
|
0
|
if(-e "$i/NCustom/Config.pm"){ |
1717
|
2
|
|
|
|
|
22
|
$global_config_file = "$i/NCustom/Config.pm"; |
1718
|
4
|
|
|
|
|
109
|
last; |
1719
|
|
|
|
|
|
|
} |
1720
|
|
|
|
|
|
|
} |
1721
|
2
|
50
|
|
|
|
6
|
if( $global_config_file =~ /^dummy$/){ |
1722
|
2
|
|
|
|
|
11
|
carp "blat_myconfig: cant find global Config.pm file"; |
1723
|
2
|
|
|
|
|
14
|
return 0; |
1724
|
|
|
|
|
|
|
} |
1725
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
# copy file, without pod doco past end |
1727
|
0
|
|
|
|
|
0
|
$rc = open(SRCFILE, "< $global_config_file"); |
1728
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "blat_myconfig: open $global_config_file : $!"; return 0; } |
|
2
|
|
|
|
|
100
|
|
|
2
|
|
|
|
|
33
|
|
1729
|
|
|
|
|
|
|
|
1730
|
0
|
|
|
|
|
0
|
$rc = open(NEWFILE, "> ${myconfig_file}"); |
1731
|
1
|
50
|
|
|
|
272
|
unless($rc){carp "blat_myconfig: open ${myconfig_file}: $!"; return 0; } |
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
188
|
|
|
2
|
|
|
|
|
12
|
|
1732
|
|
|
|
|
|
|
|
1733
|
0
|
|
|
|
|
0
|
while(){ |
1734
|
1
|
100
|
|
|
|
170
|
/^__END__/ && last; |
|
1
|
|
|
|
|
14
|
|
|
0
|
|
|
|
|
0
|
|
1735
|
1
|
|
|
|
|
287
|
print NEWFILE $_ ; |
|
2
|
|
|
|
|
63
|
|
1736
|
|
|
|
|
|
|
} |
1737
|
126
|
|
|
|
|
466
|
close(SRCFILE); |
1738
|
124
|
|
|
|
|
299
|
close(NEWFILE); |
1739
|
2
|
|
|
|
|
36
|
return 1; |
1740
|
|
|
|
|
|
|
} |
1741
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
#==================================================================== |
1743
|
|
|
|
|
|
|
# config_edit |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
=item C |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
=begin example |
1748
|
|
|
|
|
|
|
|
1749
|
1
|
|
|
|
|
2
|
test_reset(); |
1750
|
1
|
50
|
|
|
|
2
|
can_ok("NCustom", qw(config_edit)) |
1751
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1752
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
=end example |
1754
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
=for example begin |
1756
|
|
|
|
|
|
|
|
1757
|
1
|
|
|
|
|
7
|
config_edit((src_fqdn => '"install.baneharbinger.com"', |
1758
|
|
|
|
|
|
|
test_url1 => '"install.baneharbinger.com/index.html"')); |
1759
|
|
|
|
|
|
|
|
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
=for example end |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
Config_edit is followed by name vaule pairs. If there is a corresponding name in the personal configuration file, then its vaule shall be updated. If there is no corresponding name then the name value shall be added to the end of the file. If there is no file it shall be created. The personal configuration file is "~/.ncustom/NCustom/MyConfig.pm". |
1765
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
If some configuration vlaues are defined in terms of other configuration values, then the order may be important. |
1767
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
=for example_testing |
1770
|
1
|
|
|
|
|
85
|
my @lines ; |
1771
|
1
|
|
|
|
|
2130
|
open(MYCFG, "< $output/.ncustom/NCustom/MyConfig.pm"); |
1772
|
1
|
|
|
|
|
3
|
@lines = ; |
1773
|
1
|
|
|
|
|
115
|
close(MYCFG); |
1774
|
1
|
50
|
|
|
|
25
|
ok( grep( /src_fqdn.*install.baneharbinger.com/, @lines) > 0 ) |
1775
|
|
|
|
|
|
|
|| diag("TEST: can edit(add) src_fqdn"); |
1776
|
1
|
50
|
|
|
|
17
|
ok( grep( /test_url1.*install.baneharbinger.com/, @lines) > 0 ) |
1777
|
|
|
|
|
|
|
|| diag("TEST: can edit(add) test_url1"); |
1778
|
|
|
|
|
|
|
# |
1779
|
1
|
|
|
|
|
44
|
&NCustom::blat_myconfig(); #TODO# hmmm tests should be independent |
1780
|
1
|
|
|
|
|
896
|
&NCustom::config_edit((test_data1 => "wow", test_data2 => "whoopee doo")); |
1781
|
1
|
|
|
|
|
265
|
open(MYCFG, "< $output/.ncustom/NCustom/MyConfig.pm"); |
1782
|
1
|
|
|
|
|
6
|
@lines = ; |
1783
|
1
|
|
|
|
|
54
|
close(MYCFG); |
1784
|
1
|
50
|
|
|
|
52
|
ok( grep( /test_data1.*wow/, @lines) > 0 ) |
1785
|
|
|
|
|
|
|
|| diag("TEST: can edit(change) test_data1"); |
1786
|
1
|
50
|
|
|
|
13
|
ok( grep( /test_data2.*whoopee doo/, @lines) > 0 ) |
1787
|
|
|
|
|
|
|
|| diag("TEST: can edit(change) test_data2"); |
1788
|
|
|
|
|
|
|
# |
1789
|
1
|
|
|
|
|
26
|
output(); |
1790
|
|
|
|
|
|
|
|
1791
|
1
|
|
|
|
|
383
|
|
1792
|
1
|
|
|
|
|
309
|
=cut |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
#==================================================================== |
1795
|
1
|
|
|
|
|
5
|
sub config_edit { |
1796
|
1
|
|
|
2
|
1
|
7
|
my (%config_edit) = @_; |
|
2
|
|
|
|
|
94
|
|
1797
|
|
|
|
|
|
|
|
1798
|
1
|
|
|
|
|
2
|
my ($rc, $name, $value) ; |
|
2
|
|
|
|
|
9
|
|
1799
|
1
|
|
|
|
|
3
|
my $myconfig_file_dir = "$ENV{'HOME'}/.ncustom/NCustom"; |
|
2
|
|
|
|
|
29
|
|
1800
|
1
|
|
|
|
|
2
|
my $myconfig_file = "$myconfig_file_dir/MyConfig.pm"; |
|
2
|
|
|
|
|
11
|
|
1801
|
2
|
|
|
|
|
18
|
my $global_config_file = "dummy" ; |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
# ensure target directory exists |
1804
|
2
|
100
|
|
|
|
17
|
if( ! -e $myconfig_file_dir){ |
1805
|
2
|
|
|
|
|
15
|
$rc = mkpath $myconfig_file_dir; |
1806
|
2
|
50
|
|
|
|
1191
|
unless($rc){ carp "config_edit: mkpath $myconfig_file_dir: $!"; return 0; } |
|
1
|
|
|
|
|
375
|
|
|
1
|
|
|
|
|
14
|
|
1807
|
|
|
|
|
|
|
} |
1808
|
0
|
50
|
|
|
|
0
|
if( ! -d $myconfig_file_dir){ |
1809
|
0
|
|
|
|
|
0
|
carp "config_edit: not at directory: $myconfig_file_dir"; return 0; |
|
2
|
|
|
|
|
56
|
|
1810
|
|
|
|
|
|
|
} |
1811
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
# create blank personal config file if there isnt one |
1813
|
0
|
100
|
|
|
|
0
|
if( ! -e $myconfig_file){ |
1814
|
0
|
|
|
|
|
0
|
$rc = open(NEWFILE, ">$myconfig_file"); |
1815
|
2
|
50
|
|
|
|
52
|
unless($rc){carp "config_edit: open $myconfig_file: $!"; return 0; } |
|
1
|
|
|
|
|
102
|
|
|
1
|
|
|
|
|
13
|
|
1816
|
0
|
|
|
|
|
0
|
my $content = <<' EOF' ; |
1817
|
|
|
|
|
|
|
package NCustom ; |
1818
|
|
|
|
|
|
|
no warnings; |
1819
|
|
|
|
|
|
|
1; |
1820
|
|
|
|
|
|
|
EOF |
1821
|
0
|
|
|
|
|
0
|
print NEWFILE $content ; |
1822
|
1
|
|
|
|
|
6
|
close(NEWFILE); |
1823
|
|
|
|
|
|
|
} |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
# open files for editting |
1826
|
1
|
|
|
|
|
417
|
$rc = open(OLDFILE, "< ${myconfig_file}"); |
1827
|
1
|
50
|
|
|
|
48
|
unless($rc){carp "config_edit: open ${myconfig_file}: $!"; return 0; } |
|
2
|
|
|
|
|
92
|
|
|
2
|
|
|
|
|
14
|
|
1828
|
|
|
|
|
|
|
|
1829
|
0
|
|
|
|
|
0
|
$rc = open(NEWFILE, "> ${myconfig_file}.new"); |
1830
|
0
|
50
|
|
|
|
0
|
unless($rc){carp "config_edit: open ${myconfig_file}.new: $!"; return 0; } |
|
2
|
|
|
|
|
172
|
|
|
2
|
|
|
|
|
14
|
|
1831
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
# do options that are already in the file |
1833
|
0
|
|
|
|
|
0
|
while(){ |
1834
|
0
|
|
|
|
|
0
|
my $line = $_ ; |
1835
|
2
|
|
|
|
|
33
|
my $line_replaced = 0; |
1836
|
1
|
100
|
|
|
|
2
|
next if($line =~ /^\s*1;/) ; # we will add it back on later |
|
65
|
|
|
|
|
84
|
|
1837
|
65
|
|
|
|
|
224
|
while(($name, $value) = each(%config_edit)) { |
1838
|
65
|
100
|
|
|
|
163
|
if($line =~ /^\s*\$Config{.$name.}/ ){ #TODO#nasty pattern assumptions!!! |
1839
|
1
|
|
|
|
|
255
|
#print NEWFILE "\$Config{\'$name\'} = \"$value\" ; \n"; |
|
1
|
|
|
|
|
22
|
|
1840
|
1
|
|
|
|
|
449
|
print NEWFILE "\$Config{\'$name\'} = $value ; \n"; |
|
63
|
|
|
|
|
992
|
|
1841
|
37
|
|
|
|
|
2739
|
$line_replaced = 1; |
1842
|
2
|
|
|
|
|
13
|
delete($config_edit{$name}); |
1843
|
|
|
|
|
|
|
} |
1844
|
|
|
|
|
|
|
} |
1845
|
2
|
100
|
|
|
|
4
|
print NEWFILE $line unless $line_replaced ; |
1846
|
|
|
|
|
|
|
} |
1847
|
2
|
|
|
|
|
12
|
close(OLDFILE); |
1848
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
# do options that were not in the file |
1850
|
63
|
|
|
|
|
927
|
while(($name, $value) = each(%config_edit)) { |
1851
|
|
|
|
|
|
|
#print NEWFILE "\$Config{\'$name\'} = \"$value\" ;\n"; |
1852
|
2
|
|
|
|
|
22
|
print NEWFILE "\$Config{\'$name\'} = $value ;\n"; |
1853
|
|
|
|
|
|
|
} |
1854
|
2
|
|
|
|
|
9
|
print NEWFILE "1;\n"; # we said we would add it back later |
1855
|
2
|
|
|
|
|
9
|
close(NEWFILE); |
1856
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
# all done |
1858
|
2
|
|
|
|
|
4
|
$rc = move("${myconfig_file}.new", "${myconfig_file}"); |
1859
|
2
|
50
|
|
|
|
91
|
unless($rc){carp "config_edit: move $!"; return 0; } |
|
2
|
|
|
|
|
42
|
|
|
2
|
|
|
|
|
13963
|
|
1860
|
|
|
|
|
|
|
|
1861
|
0
|
|
|
|
|
0
|
return 1; |
1862
|
|
|
|
|
|
|
} |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
#==================================================================== |
1865
|
|
|
|
|
|
|
# ncustom |
1866
|
|
|
|
|
|
|
|
1867
|
|
|
|
|
|
|
=item C |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
=begin example |
1870
|
|
|
|
|
|
|
|
1871
|
1
|
|
|
|
|
4
|
test_reset(); |
1872
|
1
|
50
|
|
|
|
2
|
can_ok("NCustom", qw(ncustom)) |
1873
|
|
|
|
|
|
|
|| diag("TEST: is a public function of NCustom"); |
1874
|
1
|
|
|
|
|
6
|
copy("$input/test1.ncus", "$output"); |
1875
|
1
|
|
|
|
|
84
|
chmod(0750,"$output/test1.ncus"); |
1876
|
1
|
|
|
|
|
1008
|
copy("$input/test2.ncus", "$output"); |
1877
|
1
|
|
|
|
|
999
|
chmod(0750,"$output/test2.ncus"); |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
=end example |
1880
|
|
|
|
|
|
|
|
1881
|
|
|
|
|
|
|
=for example begin |
1882
|
|
|
|
|
|
|
|
1883
|
1
|
|
|
|
|
19
|
ncustom(<<' EOF'); |
1884
|
|
|
|
|
|
|
~/test1.ncus |
1885
|
|
|
|
|
|
|
test2.ncus |
1886
|
|
|
|
|
|
|
EOF |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
=for example end |
1889
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
Ncustom is passed one or more filenames, either local filenames or URLs. |
1891
|
|
|
|
|
|
|
The filenames are assumed to be NCustom scripts, are fetched, and executed. |
1892
|
|
|
|
|
|
|
If the filename is not an NCustom script, then transactions will not be journalled, and will not be able to be undone. |
1893
|
|
|
|
|
|
|
An unqualified NCustom script name will be searched for in pwd and the location(s) specified in NCustom::Config. |
1894
|
|
|
|
|
|
|
URLs will be fetched using the get_url subrouting in NCustom::Config. |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
=for example_testing |
1897
|
1
|
|
|
|
|
510
|
open(STUBSLOG, "< $output/stubs.log"); |
1898
|
1
|
|
|
|
|
22
|
my @lines = ; |
1899
|
1
|
|
|
|
|
102
|
close(STUBSLOG); |
1900
|
1
|
50
|
|
|
|
54
|
ok( grep( /NCustom test1.ncus/, @lines) > 0 ) |
1901
|
|
|
|
|
|
|
|| diag("TEST: fetches and executes file 1/2"); |
1902
|
1
|
50
|
|
|
|
18
|
ok( grep( /NCustom test2.ncus/, @lines) > 0 ) |
1903
|
|
|
|
|
|
|
|| diag("TEST: fetches and executes file 2/2"); |
1904
|
|
|
|
|
|
|
# |
1905
|
1
|
|
|
|
|
53
|
output(); |
1906
|
|
|
|
|
|
|
|
1907
|
1
|
|
|
|
|
768
|
=cut |
1908
|
1
|
|
|
|
|
312
|
|
1909
|
|
|
|
|
|
|
#==================================================================== |
1910
|
|
|
|
|
|
|
sub ncustom { |
1911
|
1
|
|
|
1
|
1
|
5
|
my ($file_list, @rest) = @_ ; |
|
0
|
|
|
|
|
0
|
|
1912
|
1
|
|
|
|
|
4
|
my $status = 1; |
|
2
|
|
|
|
|
18
|
|
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
#tag# |
1915
|
1
|
|
|
|
|
6
|
my @lines = split(/\n/,$file_list); |
1916
|
1
|
|
|
|
|
5
|
foreach my $line (@lines){ |
1917
|
1
|
|
|
|
|
10
|
my $executed = 0; #we must invoked something for a line |
1918
|
1
|
|
|
|
|
7
|
chomp $line ; |
1919
|
2
|
|
|
|
|
7
|
$line =~ s/^\s+//; #trim leading whitespace |
1920
|
2
|
50
|
|
|
|
8
|
next if $line =~ /^#/; #TODO# comments need much work |
1921
|
2
|
100
|
|
|
|
64
|
if(ncustom_try_dir($line, "")){$executed = 1} |
|
2
|
|
|
|
|
20
|
|
1922
|
2
|
100
|
|
|
|
19
|
if($executed){next} |
|
1
|
|
|
|
|
15
|
|
1923
|
2
|
50
|
|
|
|
26
|
if(ncustom_try_url($line, "")){$executed = 1} |
|
1
|
|
|
|
|
8
|
|
1924
|
1
|
50
|
|
|
|
17
|
if($executed){next} |
|
0
|
|
|
|
|
0
|
|
1925
|
1
|
|
|
|
|
12
|
my $src_arraryref = $NCustom::Config{'default_src'}; |
1926
|
0
|
|
|
|
|
0
|
foreach my $src (@$src_arraryref){ |
1927
|
1
|
|
|
|
|
7
|
my $dir = (glob($src))[0]; |
1928
|
1
|
50
|
|
|
|
7
|
if(-d $dir){ |
1929
|
1
|
50
|
|
|
|
40
|
if(ncustom_try_dir($line, $dir)){$executed = 1} |
|
1
|
|
|
|
|
27
|
|
1930
|
1
|
50
|
|
|
|
7
|
if($executed){last}; |
|
1
|
|
|
|
|
18
|
|
1931
|
|
|
|
|
|
|
}else{ |
1932
|
1
|
0
|
|
|
|
15
|
if(ncustom_try_url($line, $src)){$executed = 1} |
|
1
|
|
|
|
|
13
|
|
1933
|
0
|
0
|
|
|
|
0
|
if($executed){last}; |
|
0
|
|
|
|
|
0
|
|
1934
|
|
|
|
|
|
|
} |
1935
|
|
|
|
|
|
|
} |
1936
|
0
|
50
|
|
|
|
0
|
if($executed){next} |
|
0
|
|
|
|
|
0
|
|
1937
|
1
|
|
|
|
|
11
|
carp "ncustom: cant find/execute \"$line\".\n"; |
1938
|
1
|
|
|
|
|
20
|
$status = 0; |
1939
|
|
|
|
|
|
|
} |
1940
|
0
|
|
|
|
|
0
|
return $status; |
1941
|
|
|
|
|
|
|
} |
1942
|
|
|
|
|
|
|
|
1943
|
|
|
|
|
|
|
#==================================================================== |
1944
|
|
|
|
|
|
|
sub ncustom_try_dir { |
1945
|
0
|
|
|
3
|
0
|
0
|
my ($line, $prefix, @rest) = @_ ; |
1946
|
1
|
|
|
|
|
22
|
my (@candidates, $candidate); |
1947
|
3
|
|
|
|
|
24
|
my $executed = 0 ; |
1948
|
3
|
|
|
|
|
13
|
my $rc ; |
1949
|
|
|
|
|
|
|
|
1950
|
3
|
|
|
|
|
7
|
@candidates = glob($line); |
1951
|
3
|
|
|
|
|
7
|
foreach $candidate (@candidates){ |
1952
|
3
|
|
|
|
|
175
|
my $file = (glob("${prefix}${candidate}"))[0]; |
1953
|
3
|
100
|
66
|
|
|
12
|
if(-f $file && -x $file){ |
1954
|
3
|
50
|
|
|
|
85
|
if( basename($file) eq $file){ |
1955
|
3
|
|
|
|
|
126
|
$file = "./$file"; |
1956
|
|
|
|
|
|
|
# so system call ok in this scenario (regardless of pwd being in path) |
1957
|
|
|
|
|
|
|
} |
1958
|
2
|
|
|
|
|
204
|
$rc = system($file); |
1959
|
0
|
50
|
|
|
|
0
|
carp "ncustom_try_dir: system call=$file : error=$?\n" unless $rc == 0; |
1960
|
2
|
|
|
|
|
32925
|
$executed = 1; |
1961
|
|
|
|
|
|
|
#for better or worse... |
1962
|
|
|
|
|
|
|
} |
1963
|
|
|
|
|
|
|
} |
1964
|
2
|
|
|
|
|
60
|
return $executed; |
1965
|
|
|
|
|
|
|
} |
1966
|
|
|
|
|
|
|
|
1967
|
|
|
|
|
|
|
#==================================================================== |
1968
|
|
|
|
|
|
|
sub ncustom_try_url { |
1969
|
2
|
|
|
1
|
0
|
58
|
my ($line, $prefix, @rest) = @_ ; |
1970
|
3
|
|
|
|
|
84
|
my (@candidates, $candidate); |
1971
|
1
|
|
|
|
|
10
|
my $executed = 0 ; |
1972
|
1
|
|
|
|
|
7
|
my $rc ; |
1973
|
|
|
|
|
|
|
|
1974
|
1
|
|
|
|
|
3
|
my $stagedir = tempdir( DIR => $Config{'tmp_dir'}); |
1975
|
|
|
|
|
|
|
#TODO# add CLEANUP => 1 |
1976
|
1
|
|
|
|
|
8
|
my $subref = $NCustom::Config{'get_url'}; |
1977
|
1
|
|
|
|
|
35
|
&$subref("${prefix}${line}",$stagedir); |
1978
|
1
|
|
|
|
|
738
|
opendir(DIR, $stagedir); |
1979
|
1
|
50
|
|
|
|
164
|
@candidates = grep { -f $_ && -x $_ } # executable files only |
|
1
|
|
|
|
|
29
|
|
1980
|
1
|
|
|
|
|
17
|
map { "$stagedir/$_" } # form: "path/filename" |
1981
|
|
|
|
|
|
|
readdir(DIR); # all files |
1982
|
2
|
|
|
|
|
61
|
foreach $candidate (@candidates){ |
1983
|
2
|
|
|
|
|
14
|
$rc = system($candidate); |
1984
|
1
|
0
|
|
|
|
7
|
carp "ncustom_try_url: system call=${candidate}: error=$?\n" unless $rc ==0; |
1985
|
0
|
|
|
|
|
0
|
$executed = 1; |
1986
|
|
|
|
|
|
|
#for better or worse... |
1987
|
|
|
|
|
|
|
} |
1988
|
0
|
|
|
|
|
0
|
return $executed; |
1989
|
|
|
|
|
|
|
} |
1990
|
|
|
|
|
|
|
#==================================================================== |
1991
|
|
|
|
|
|
|
|
1992
|
|
|
|
|
|
|
# /////////////////////////////////////////////////////////////////// |
1993
|
|
|
|
|
|
|
#<< CC: Constructor <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
1994
|
|
|
|
|
|
|
# \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
1995
|
|
|
|
|
|
|
constructor(); |
1996
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
sub constructor { |
1998
|
0
|
|
|
18
|
0
|
0
|
load_config(); |
1999
|
1
|
|
|
|
|
7
|
apply_config(); |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
# /////////////////////////////////////////////////////////////////// |
2003
|
|
|
|
|
|
|
#<< DD: Destructor <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
2004
|
|
|
|
|
|
|
# \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
2005
|
|
|
|
|
|
|
# Dont clean up on exit of tests, |
2006
|
|
|
|
|
|
|
# or we would have nothing to diagnose upon failure of tests, |
2007
|
|
|
|
|
|
|
# instead we prevent polution by doing a cleanup prior to each test, |
2008
|
|
|
|
|
|
|
# this is also better as destructor isnt 100% reliable, depending upon death. |
2009
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
1; |
2011
|
|
|
|
|
|
|
__END__ |