line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Config::Ant; |
2
|
|
|
|
|
|
|
BEGIN { |
3
|
2
|
|
|
2
|
|
45107
|
$Config::Ant::VERSION = '0.01'; |
4
|
|
|
|
|
|
|
} |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Load Ant-style property files |
7
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
18
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
59
|
|
9
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
53
|
|
10
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
19
|
use Carp; |
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
317
|
|
12
|
2
|
|
|
2
|
|
18
|
use Scalar::Util qw(openhandle); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
253
|
|
13
|
2
|
|
|
2
|
|
1973
|
use File::Slurp qw(read_file); |
|
2
|
|
|
|
|
41129
|
|
|
2
|
|
|
|
|
1821
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
16
|
2
|
|
|
2
|
1
|
27
|
my ($this, @initial) = @_; |
17
|
2
|
|
33
|
|
|
16
|
my $class = ref($this) || $this; |
18
|
2
|
|
|
|
|
7
|
my $self = {@initial}; |
19
|
2
|
|
|
|
|
5
|
bless $self, $class; |
20
|
2
|
|
|
|
|
8
|
return $self; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub read { |
24
|
4
|
|
|
4
|
1
|
3003
|
my ($self, $file) = @_; |
25
|
4
|
|
|
|
|
18
|
my $contents = File::Slurp::read_file($file); |
26
|
4
|
|
|
|
|
385
|
$self->read_string($contents); |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub read_line { |
30
|
14
|
|
|
14
|
1
|
38
|
my ($self, $section, $key, $value) = @_; |
31
|
|
|
|
|
|
|
|
32
|
14
|
100
|
|
|
|
40
|
return if (exists($self->{$section}->{$key})); |
33
|
|
|
|
|
|
|
|
34
|
12
|
|
|
|
|
55
|
$value =~ s/\$\{([^}]+)\}/ |
35
|
10
|
100
|
|
|
|
34
|
if (! exists($self->{$section}->{$1})) { |
36
|
2
|
|
|
|
|
9
|
'${'.$1.'}'; |
37
|
|
|
|
|
|
|
} else { |
38
|
8
|
|
|
|
|
33
|
$self->{$section}->{$1}; |
39
|
|
|
|
|
|
|
} /eg; |
40
|
|
|
|
|
|
|
|
41
|
12
|
|
|
|
|
42
|
$self->{$section}->{$key} = $value; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# This has been cobbled from Config::Tiny. Most of the rest has been |
45
|
|
|
|
|
|
|
# written directly using additional dependencies. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub read_string { |
48
|
4
|
|
|
4
|
1
|
8
|
my ($self, $contents) = @_; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# Parse the file |
51
|
4
|
|
|
|
|
6
|
my $ns = '_'; |
52
|
4
|
|
|
|
|
6
|
my $counter = 0; |
53
|
4
|
|
|
|
|
184
|
foreach ( split /(?:\015{1,2}\012|\015|\012)/, $contents ) { |
54
|
34
|
|
|
|
|
35
|
$counter++; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Skip comments and empty lines |
57
|
34
|
100
|
|
|
|
100
|
next if /^\s*(?:\#|\;|$)/; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Remove inline comments |
60
|
14
|
|
|
|
|
21
|
s/\s\;\s.+$//g; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# Handle section headers |
63
|
14
|
50
|
|
|
|
34
|
if ( /^\s*\[\s*(.+?)\s*\]\s*$/ ) { |
64
|
|
|
|
|
|
|
# Create the sub-hash if it doesn't exist. |
65
|
|
|
|
|
|
|
# Without this sections without keys will not |
66
|
|
|
|
|
|
|
# appear at all in the completed struct. |
67
|
0
|
|
0
|
|
|
0
|
$self->{$ns = $1} ||= {}; |
68
|
0
|
|
|
|
|
0
|
next; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# Handle properties |
72
|
14
|
50
|
|
|
|
107
|
if ( /^\s*([^=]+?)\s*=\s*(.*?)\s*$/ ) { |
73
|
14
|
|
|
|
|
33
|
$self->read_line($ns, $1, $2); |
74
|
14
|
|
|
|
|
26
|
next; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
0
|
return $self->_error( "Syntax error at line $counter: '$_'" ); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
4
|
|
|
|
|
17
|
$self; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub write { |
84
|
1
|
|
|
1
|
1
|
885
|
my ($self, $file) = @_; |
85
|
|
|
|
|
|
|
|
86
|
1
|
|
|
|
|
2
|
my $opened = 0; |
87
|
1
|
50
|
|
|
|
8
|
if (! openhandle($file)) { |
88
|
0
|
0
|
|
|
|
0
|
open($file, '>', $file) or croak("Failed to open file '$file' for writing: $!"); |
89
|
0
|
|
|
|
|
0
|
$opened = 1; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
1
|
|
|
|
|
14
|
print $file $self->write_string(); |
93
|
1
|
50
|
|
|
|
5
|
close($file) if ($opened); |
94
|
1
|
|
|
|
|
23
|
return; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# Again, this bit was cobbled from Config::Tiny. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub write_string { |
100
|
1
|
|
|
1
|
1
|
2
|
my ($self) = @_; |
101
|
|
|
|
|
|
|
|
102
|
1
|
|
|
|
|
2
|
my $contents = ''; |
103
|
1
|
0
|
|
|
|
5
|
foreach my $section ( sort { (($b eq '_') <=> ($a eq '_')) || ($a cmp $b) } keys %$self ) { |
|
0
|
|
|
|
|
0
|
|
104
|
1
|
|
|
|
|
3
|
my $block = $self->{$section}; |
105
|
1
|
50
|
|
|
|
11
|
$contents .= "\n" if length $contents; |
106
|
1
|
50
|
|
|
|
4
|
$contents .= "[$section]\n" unless $section eq '_'; |
107
|
1
|
|
|
|
|
7
|
foreach my $property ( sort keys %$block ) { |
108
|
6
|
|
|
|
|
16
|
$contents .= "$property=$block->{$property}\n"; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
1
|
|
|
|
|
14
|
$contents; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
1; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head1 NAME |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Config::Ant - load Ant-style property files |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head1 SYNOPSIS |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# In your configuration file |
124
|
|
|
|
|
|
|
root.directory = /usr/local |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
lib = ${root.directory}/lib |
127
|
|
|
|
|
|
|
bin = ${root.directory}/lib |
128
|
|
|
|
|
|
|
perl = ${bin}/perl |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# In your program |
131
|
|
|
|
|
|
|
use Config::Ant; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Create a config |
134
|
|
|
|
|
|
|
my $config = Config::Ant->new(); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Read the config |
137
|
|
|
|
|
|
|
$config->read('file1.conf'); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# You can also read a second file, with properties substituted from the first |
140
|
|
|
|
|
|
|
$config->read('file2.conf'); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my $rootdir = $config->{_}->{'root.directory'}; |
143
|
|
|
|
|
|
|
my $perl = $config->{_}->{perl}; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# Writing ignores substitutions |
146
|
|
|
|
|
|
|
$config->write('files.conf'); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head1 DESCRIPTION |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Apache Ant uses property files with substitutions in them, which are very helpful for maintaining |
151
|
|
|
|
|
|
|
a complex set of related properties. This component is a subclass of L which includes |
152
|
|
|
|
|
|
|
the Ant-style substitution systems. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Ant properties are set by their first definition and are then immutable, so a second definition |
155
|
|
|
|
|
|
|
will not affect anything, ever. This is handy, as you can override settings by putting local values |
156
|
|
|
|
|
|
|
first, and the loading files of defaults. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Note that the usage interface is I identical to L. This is because L |
159
|
|
|
|
|
|
|
assumes that each file is self-contained, and constructs a new object for it. This does not make |
160
|
|
|
|
|
|
|
sense for Ant-style files, which are often loaded from several files, allowing for local customization. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Also not that the file format is I identical to Ant, in that like L, |
163
|
|
|
|
|
|
|
Config::Ant allows "windows style" sections to be used. This can be handy, but it's an optional extra |
164
|
|
|
|
|
|
|
that will only annoy you if you use property names containing [ or ], which would be a very |
165
|
|
|
|
|
|
|
bad move. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 METHODS |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=over 4 |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item Config::Ant->new() |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Returns a new property file processing instance, which can then be used as a container for |
174
|
|
|
|
|
|
|
properties read and written through the other methods. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=item read($file) |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Reads a file (or file handle) into the property system. This reads the text and passes the string to |
179
|
|
|
|
|
|
|
C. This method can be called many times for a single instance, and this is common |
180
|
|
|
|
|
|
|
when you want to handle several property files. The first property sets always wins, and there is |
181
|
|
|
|
|
|
|
no method defined to allow properties to be removed. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item read_string($text) |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Reads and processes the properties a line at a time. Comment lines and blanks are skipped, sections |
186
|
|
|
|
|
|
|
are set, and property lines passed to C |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=item read_line($section, $property, $value) |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
This sets the property, and can be overridden if required. The property will only be set if a value |
191
|
|
|
|
|
|
|
doesn't exist. The default method also handles the substitution of existing values into the value. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item write($file) |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Opens the file for writing, if necessary (i.e., not a file handle) and then writes out all the |
196
|
|
|
|
|
|
|
current properties, using C to obtain the stringified property file text. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=item write_string() |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Returns the stringified text for all the properties currently registered. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=back |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head1 AUTHOR |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Stuart Watt Estuart@morungos.comE |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head1 COPYRIGHT |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Copyright 2010 by the authors. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head1 SEE ALSO |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Partly based on L. |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=cut |