line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Win32::TieRegistry::PMVersionInfo;
|
2
|
1
|
|
|
1
|
|
5056
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
56
|
|
3
|
|
|
|
|
|
|
our $VERSION = 0.2;
|
4
|
|
|
|
|
|
|
our $CHAT;
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Win32::TieRegistry::PMVersionInfo - store in Win32 Registry PM $VERSION info
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Win32::TieRegistry::PMVersionInfo 0.2;
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my $reg = new Win32::TieRegistry::PMVersionInfo (
|
15
|
|
|
|
|
|
|
file_root => "D:/src/pl/spc2xml/version5/",
|
16
|
|
|
|
|
|
|
ignore_dirs => ["Commercial/bin/",
|
17
|
|
|
|
|
|
|
"Commercial/SPC/XSLT/SourceForge",
|
18
|
|
|
|
|
|
|
"Commercial/SPC/XSLT/CSS",
|
19
|
|
|
|
|
|
|
"Commercial/SPC/XSLT/imgs",],
|
20
|
|
|
|
|
|
|
reg_root => 'LMachine/Software/LittleBits/',
|
21
|
|
|
|
|
|
|
strip_path => $strip_path,
|
22
|
|
|
|
|
|
|
chat=>1,
|
23
|
|
|
|
|
|
|
);
|
24
|
|
|
|
|
|
|
$reg->get;
|
25
|
|
|
|
|
|
|
$reg->store;
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
exit;
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This module mirrors to the Win32 registry version information from a perl module's heirachy.
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
It offers no support for reading the information - for that use the C module
|
34
|
|
|
|
|
|
|
on which this module is based.
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Version information is ascertained using the same method as in C version 5.45.
|
37
|
|
|
|
|
|
|
To quote that module's manpage:
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
The first line in the file that contains the regular expression
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
will be evaluated with eval() and the value of the named variable
|
44
|
|
|
|
|
|
|
after the eval() will be assigned to the VERSION attribute of the
|
45
|
|
|
|
|
|
|
MakeMaker object. The following lines will be parsed o.k.:
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
$VERSION = '1.00';
|
48
|
|
|
|
|
|
|
*VERSION = \'1.01';
|
49
|
|
|
|
|
|
|
( $VERSION ) = '$Revision: 1.222 $ ' =~ /\$Revision:\s+([^\s]+)/;
|
50
|
|
|
|
|
|
|
$FOO::VERSION = '1.10';
|
51
|
|
|
|
|
|
|
*FOO::VERSION = \'1.11';
|
52
|
|
|
|
|
|
|
our $VERSION = 1.2.3; # new for perl5.6.0
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
but these will fail:
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
my $VERSION = '1.01';
|
57
|
|
|
|
|
|
|
local $VERSION = '1.02';
|
58
|
|
|
|
|
|
|
local $FOO::VERSION = '1.30';
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
(Putting "my" or "local" on the preceding line will work o.k.)
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 DEPENDENCIES
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Win32::TieRegistry.
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=cut
|
67
|
|
|
|
|
|
|
|
68
|
1
|
|
|
1
|
|
1351
|
use Win32::TieRegistry ( Delimiter=>"/" );
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
use Carp;
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head1 CONSTRUCTOR
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Expects a class name, and optionally a list of arguments in a hash-like structure, a hash or pointer to a hash.
|
74
|
|
|
|
|
|
|
Options are keys in a the blessed hash reference that is the object, and as such may be directly accessed anytime.
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Options are:
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=over 4
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item file_root
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
The root at which to be begin parsing files.
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item ignore_dirs
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
An array of directories above the C not to process.
|
87
|
|
|
|
|
|
|
If any directory encountered matches at the beginning of one of
|
88
|
|
|
|
|
|
|
these strings, it will not be processed.
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=item strip_path
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
The text to strip from left-hand side of paths when storing in the registry.
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=item reg_root
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
The branch at which to root the mirror of the directory structure.
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item dirname_pattern
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
A positve regular expressions used when reading a directory, which the module
|
101
|
|
|
|
|
|
|
encloses within the bracket 'grouping' operator and anchors to the begining and
|
102
|
|
|
|
|
|
|
end of the string being matched. The C<.> and C<..> directories are excluded.
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item filename_pattern
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
As C above, but applies to filenames, and defaults to C<.*>.
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=item extension
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Set to anything to retain the file extension when mapping to the registry (the default);
|
111
|
|
|
|
|
|
|
expilcitly set to C to strip from the filename everything after the last full-stop.
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=back
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=cut
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub new { my ($class) = (shift);
|
118
|
|
|
|
|
|
|
unless (defined $class) {
|
119
|
|
|
|
|
|
|
warn "Usage: $class->new( {key=>value} )";
|
120
|
|
|
|
|
|
|
return undef;
|
121
|
|
|
|
|
|
|
}
|
122
|
|
|
|
|
|
|
my %args;
|
123
|
|
|
|
|
|
|
# Take parameters and place in object slots/set as instance variables
|
124
|
|
|
|
|
|
|
if (ref $_[0] eq 'HASH'){ %args = %{$_[0]} }
|
125
|
|
|
|
|
|
|
elsif (not ref $_[0]){ %args = @_ }
|
126
|
|
|
|
|
|
|
else {
|
127
|
|
|
|
|
|
|
warn "Usage: $class->new( { key=>values, } )";
|
128
|
|
|
|
|
|
|
return undef;
|
129
|
|
|
|
|
|
|
}
|
130
|
|
|
|
|
|
|
my $self = bless {},$class;
|
131
|
|
|
|
|
|
|
# Set default options that may be over-ridden
|
132
|
|
|
|
|
|
|
$self->{tree} = ();
|
133
|
|
|
|
|
|
|
$self->{file_root} = '';
|
134
|
|
|
|
|
|
|
$self->{ignore_dirs} = [];
|
135
|
|
|
|
|
|
|
$self->{reg_root} = '';
|
136
|
|
|
|
|
|
|
$self->{strip_path} = '';
|
137
|
|
|
|
|
|
|
$self->{filename_pattern} = '.*';
|
138
|
|
|
|
|
|
|
$self->{dirname_pattern} = '.*';
|
139
|
|
|
|
|
|
|
$self->{extension} = 1;
|
140
|
|
|
|
|
|
|
# Set/overwrite public slots with user's values
|
141
|
|
|
|
|
|
|
foreach (keys %args) { $self->{lc $_} = $args{$_} }
|
142
|
|
|
|
|
|
|
if (exists $self->{chat} and defined $self->{chat}){
|
143
|
|
|
|
|
|
|
$CHAT = 1;
|
144
|
|
|
|
|
|
|
}
|
145
|
|
|
|
|
|
|
if (ref $self->{ignore_dirs} ne 'ARRAY'){
|
146
|
|
|
|
|
|
|
carp "Not an array ref";
|
147
|
|
|
|
|
|
|
}
|
148
|
|
|
|
|
|
|
# Try to create the root key if it doesn't exist
|
149
|
|
|
|
|
|
|
$_ = $Registry->{ $self->{reg_root} };
|
150
|
|
|
|
|
|
|
$Registry->{ $self->{reg_root} } = {} if not defined $_;
|
151
|
|
|
|
|
|
|
$_ = $Registry->{ $self->{reg_root} };
|
152
|
|
|
|
|
|
|
return $self;
|
153
|
|
|
|
|
|
|
}
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head2 METHOD get
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Accepts an object reference, and optionally a directory to parse. Stores the names of all the files
|
158
|
|
|
|
|
|
|
in the passed directory (or the calling object's C slot),
|
159
|
|
|
|
|
|
|
and recurses (calls itself) on all sub-directories. Incidentally returns the path to the
|
160
|
|
|
|
|
|
|
directory operated upon.
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Will return without reiterating if the directory passed matches at the beginning of
|
163
|
|
|
|
|
|
|
any string in the C list (ie. the value in the object's C
|
164
|
|
|
|
|
|
|
plus C<@{$self->{ignore_dirs}}> slot).
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
See L for details of how to effect exclusion of file and directory names.
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
See also L above for details of how the version is ascertained.
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=cut
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub get { my ($self,$dir) = (shift,shift);
|
173
|
|
|
|
|
|
|
local *DIR;
|
174
|
|
|
|
|
|
|
$dir = $self->{file_root} if not defined $dir;
|
175
|
|
|
|
|
|
|
croak "No \$self->{file_root} or passed dir to parse in method 'get'" if not defined $dir or $dir eq '';
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# See if our dir, $dir, is in the ignore list, @{$self->{ignore_dirs}}
|
178
|
|
|
|
|
|
|
foreach (@{$self->{ignore_dirs}}){
|
179
|
|
|
|
|
|
|
warn "Ignoring $_\n" and return undef if $dir =~ /$self->{file_root}\/?$_/;
|
180
|
|
|
|
|
|
|
}
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
opendir DIR,$dir
|
183
|
|
|
|
|
|
|
or croak("Method get couldn't open process dir to get a file: <$dir>:\n $!.")
|
184
|
|
|
|
|
|
|
and return undef;
|
185
|
|
|
|
|
|
|
foreach my $fn (grep !-d && /^$self->{filename_pattern}$/,readdir DIR){
|
186
|
|
|
|
|
|
|
push @{$self->{tree}}, {
|
187
|
|
|
|
|
|
|
path => $dir.$fn,
|
188
|
|
|
|
|
|
|
version => &version_from($dir.$fn)
|
189
|
|
|
|
|
|
|
};
|
190
|
|
|
|
|
|
|
}
|
191
|
|
|
|
|
|
|
closedir DIR;
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
chdir $dir or $self->croak("Method get couldn't cd to dir <$dir>: $!") and return undef;
|
194
|
|
|
|
|
|
|
opendir DIR,$dir or $self->croak("Method get couldn't open dir <$dir>: $!") and return undef;
|
195
|
|
|
|
|
|
|
foreach my $next_dir (grep {-d && !/^\.\.?$/ && /^($self->{dirname_pattern})$/ } readdir DIR){
|
196
|
|
|
|
|
|
|
$self->get($dir.$next_dir.'/');
|
197
|
|
|
|
|
|
|
}
|
198
|
|
|
|
|
|
|
closedir DIR;
|
199
|
|
|
|
|
|
|
return $dir;
|
200
|
|
|
|
|
|
|
}
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
#
|
203
|
|
|
|
|
|
|
# PRIVATE SUBROUTINE version_from
|
204
|
|
|
|
|
|
|
# accepts a path, returns the version of that file or undef.
|
205
|
|
|
|
|
|
|
# Evals each line in the file until finding /([\$*])(([\w\:\']*)\bVERSION)\b.*\=/ and evaluating
|
206
|
|
|
|
|
|
|
#
|
207
|
|
|
|
|
|
|
sub version_from { my $path = shift;
|
208
|
|
|
|
|
|
|
croak "version_from called without path argument" if not defined $path;
|
209
|
|
|
|
|
|
|
local *IN;
|
210
|
|
|
|
|
|
|
my $version = undef;
|
211
|
|
|
|
|
|
|
open IN, $path;
|
212
|
|
|
|
|
|
|
while (){
|
213
|
|
|
|
|
|
|
my $VERSION;
|
214
|
|
|
|
|
|
|
next if !/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/;
|
215
|
|
|
|
|
|
|
s/^\s*(local|our)\s+//;
|
216
|
|
|
|
|
|
|
$_ = eval ("$_"); # Escape scoping?
|
217
|
|
|
|
|
|
|
$version = $VERSION;
|
218
|
|
|
|
|
|
|
last;
|
219
|
|
|
|
|
|
|
}
|
220
|
|
|
|
|
|
|
close IN;
|
221
|
|
|
|
|
|
|
warn "$version in $path\n" if $CHAT and defined $version;
|
222
|
|
|
|
|
|
|
return $version;
|
223
|
|
|
|
|
|
|
}
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head2 METHOD get_from_MANIFEST
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
As the C method, but only gets information from files listed
|
228
|
|
|
|
|
|
|
in a C file, the path to which should be passed as the first argument.
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Additionally, the name of a C file may be passed as a further argument,
|
231
|
|
|
|
|
|
|
in which case no information will be garthered from files listed therein.
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=cut
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub get_from_MANIFEST { my ($self,$manifest,$manifest_skip) = (@_);
|
236
|
|
|
|
|
|
|
croak "No manifest file passed as argument" if not defined $manifest;
|
237
|
|
|
|
|
|
|
croak "No such manifest file as $manifest" if not -e $manifest;
|
238
|
|
|
|
|
|
|
local *IN;
|
239
|
|
|
|
|
|
|
my %skip;
|
240
|
|
|
|
|
|
|
if (defined $manifest_skip){
|
241
|
|
|
|
|
|
|
croak "No such MANIFEST.SKIP file as $manifest_skip" if not -e $manifest_skip;
|
242
|
|
|
|
|
|
|
open IN, $manifest_skip;
|
243
|
|
|
|
|
|
|
while (){
|
244
|
|
|
|
|
|
|
chomp;
|
245
|
|
|
|
|
|
|
$skip{$_} = 1;
|
246
|
|
|
|
|
|
|
}
|
247
|
|
|
|
|
|
|
close IN;
|
248
|
|
|
|
|
|
|
}
|
249
|
|
|
|
|
|
|
open MANIFEST,$manifest or croak "Could not open $manifest";
|
250
|
|
|
|
|
|
|
while (){
|
251
|
|
|
|
|
|
|
chomp;
|
252
|
|
|
|
|
|
|
next if exists $skip{$_};
|
253
|
|
|
|
|
|
|
push @{$self->{tree}}, {
|
254
|
|
|
|
|
|
|
path => $_,
|
255
|
|
|
|
|
|
|
version => &version_from($_)
|
256
|
|
|
|
|
|
|
};
|
257
|
|
|
|
|
|
|
}
|
258
|
|
|
|
|
|
|
close IN;
|
259
|
|
|
|
|
|
|
return 1;
|
260
|
|
|
|
|
|
|
}
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head2 METHOD store
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Accepts an object-reference and optionally a registry path to act as a root at which to secure
|
265
|
|
|
|
|
|
|
the C<$VERSION> info from every file in the object's C slot. If no 'root' is supplied,
|
266
|
|
|
|
|
|
|
the calling object's C slot is used. Incidentally returns the root used after making
|
267
|
|
|
|
|
|
|
changes to the registry.
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=cut
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub store { my ($self,$root) = (shift,shift);
|
272
|
|
|
|
|
|
|
$root = $self->{reg_root} if not defined $root;
|
273
|
|
|
|
|
|
|
foreach my $file (sort @{$self->{tree}}){
|
274
|
|
|
|
|
|
|
if (exists $file->{version} and $file->{version} ne ''){
|
275
|
|
|
|
|
|
|
# warn $file->{path},"\t",$file->{version},"\n";
|
276
|
|
|
|
|
|
|
$file->{path} =~ s/^\Q$self->{strip_path}\E//i;
|
277
|
|
|
|
|
|
|
$file->{path} =~ s/\.[^.]*$// if defined $self->{extension};
|
278
|
|
|
|
|
|
|
$file->{path} =~ s|\\|/|g;
|
279
|
|
|
|
|
|
|
# Build the heirachy
|
280
|
|
|
|
|
|
|
my $path = $root;
|
281
|
|
|
|
|
|
|
foreach my $part (split m|/|,$file->{path}){
|
282
|
|
|
|
|
|
|
$path .= $part.'/';
|
283
|
|
|
|
|
|
|
$_ = $Registry->{ $path };
|
284
|
|
|
|
|
|
|
$Registry->{ $path } = {} if not defined $_;
|
285
|
|
|
|
|
|
|
}
|
286
|
|
|
|
|
|
|
# Make the keys from all the values in %{$file}, except $path
|
287
|
|
|
|
|
|
|
foreach (keys %{$file}){
|
288
|
|
|
|
|
|
|
next if $_ eq 'path';
|
289
|
|
|
|
|
|
|
$Registry->{ $root.$file->{path} } = {$_ => $file->{$_} };
|
290
|
|
|
|
|
|
|
}
|
291
|
|
|
|
|
|
|
} else {
|
292
|
|
|
|
|
|
|
warn "No version in file '$file->{path}'\n" if $CHAT;
|
293
|
|
|
|
|
|
|
}
|
294
|
|
|
|
|
|
|
}
|
295
|
|
|
|
|
|
|
return $root;
|
296
|
|
|
|
|
|
|
}
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
1; # Moduel must return a true value
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
__END__
|