line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
101611
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
48
|
|
2
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
46
|
|
3
|
2
|
|
|
2
|
|
920
|
use utf8; |
|
2
|
|
|
|
|
18
|
|
|
2
|
|
|
|
|
7
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package FTN::Outbound::Reference_file; |
6
|
|
|
|
|
|
|
$FTN::Outbound::Reference_file::VERSION = '20170409'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# fts-5005.002 BinkleyTerm Style Outbound |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Reference files consist of a number of lines (terminated by 0x0a or 0x0d,0x0a) each consisting of the name of the file to transfer to the remote system. |
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
712
|
use Log::Log4perl (); |
|
2
|
|
|
|
|
34342
|
|
|
2
|
|
|
|
|
31
|
|
13
|
2
|
|
|
2
|
|
764
|
use Encode::Locale (); |
|
2
|
|
|
|
|
12188
|
|
|
2
|
|
|
|
|
38
|
|
14
|
2
|
|
|
2
|
|
11
|
use Encode (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
2850
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# use File::Basename (); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my @line_joiner = ( "\x0a", |
20
|
|
|
|
|
|
|
"\x0d\x0a", |
21
|
|
|
|
|
|
|
); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my $prefix_re = qr/[-#^~!@]/; # fts-5005.002 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 NAME |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
FTN::Outbound::Reference_file - Object-oriented module for working with FTN reference files. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 VERSION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
version 20170409 |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 SYNOPSIS |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
use Log::Log4perl (); |
36
|
|
|
|
|
|
|
use Encode (); |
37
|
|
|
|
|
|
|
use FTN::Outbound::Reference_file (); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Log::Log4perl -> easy_init( $Log::Log4perl::INFO ); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my $reference_file = FTN::Outbound::Reference_file -> new( '/var/lib/ftn/outbound/fidonet/00010001.flo', |
42
|
|
|
|
|
|
|
sub { |
43
|
|
|
|
|
|
|
Encode::decode( 'cp866', shift ); |
44
|
|
|
|
|
|
|
}, |
45
|
|
|
|
|
|
|
sub { |
46
|
|
|
|
|
|
|
Encode::encode( 'cp866', shift ); |
47
|
|
|
|
|
|
|
}, |
48
|
|
|
|
|
|
|
"\x0d\x0a", |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$reference_file |
52
|
|
|
|
|
|
|
-> read_existing_file |
53
|
|
|
|
|
|
|
-> push_reference( '#', '/tmp/file_to_transfer' ) |
54
|
|
|
|
|
|
|
-> write_file; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 DESCRIPTION |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
FTN::Outbound::Reference_file module is for working with reference files in FTN following specifications from fts-5005.002 document. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 OBJECT CREATION |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 new |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
my $reference_file = FTN::Outbound::Reference_file -> new( 'filename', |
65
|
|
|
|
|
|
|
sub { |
66
|
|
|
|
|
|
|
Encode::decode( 'UTF-8', shift ); |
67
|
|
|
|
|
|
|
}, |
68
|
|
|
|
|
|
|
sub { |
69
|
|
|
|
|
|
|
Encode::encode( 'UTF-8', shift ); |
70
|
|
|
|
|
|
|
}, |
71
|
|
|
|
|
|
|
chr( 0x0a ), |
72
|
|
|
|
|
|
|
); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
First parameter is a filename as a character string. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Second parameter is either undef (in case no reading from the file expected (means file does not exist)) or sub reference that takes octet string (read from the existing reference file) and returns character string. In simplest case does just decoding from some predefined character set used by your software. Also might do other transformations. For example if other software uses relative path, this is the place where you transform it to absolute path by some rules. Output result used only in memory processing and won't be written to the file. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Third parameter is either undef (in case no updates expected) or sub reference that takes character string and returns octet stream that will be written to the file. Used only by push_reference method. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Forth parameter defines line joiner as standard allows two of them. If not defined or omitted will be either figured out from existing file (if possible) or character with code 0x0a will be used. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub new { |
85
|
2
|
|
|
2
|
1
|
3022
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
86
|
|
|
|
|
|
|
|
87
|
2
|
50
|
|
|
|
222
|
ref( my $class = shift ) and $logger -> logcroak( "I'm only a class method!" ); |
88
|
|
|
|
|
|
|
|
89
|
2
|
|
|
|
|
3
|
my ( $reference_file, |
90
|
|
|
|
|
|
|
$reference_file_read_line_transform_sub, |
91
|
|
|
|
|
|
|
$reference_file_write_line_transform_sub, |
92
|
|
|
|
|
|
|
$line_joiner, |
93
|
|
|
|
|
|
|
) = @_; |
94
|
|
|
|
|
|
|
|
95
|
2
|
50
|
|
|
|
6
|
$logger -> logdie( 'reference file name cannot be undefined' ) |
96
|
|
|
|
|
|
|
unless defined $reference_file; |
97
|
|
|
|
|
|
|
|
98
|
2
|
|
|
|
|
11
|
$logger -> debug( sprintf 'reference file name %s', |
99
|
|
|
|
|
|
|
$reference_file, |
100
|
|
|
|
|
|
|
); |
101
|
|
|
|
|
|
|
|
102
|
2
|
|
|
|
|
17
|
my %self = ( reference_file => $reference_file ); |
103
|
|
|
|
|
|
|
|
104
|
2
|
50
|
33
|
|
|
17
|
$logger -> logdie( 'not valid reference file read line transform subroutine reference was passed as second argument' ) |
105
|
|
|
|
|
|
|
if defined $reference_file_read_line_transform_sub |
106
|
|
|
|
|
|
|
&& ref $reference_file_read_line_transform_sub ne 'CODE'; |
107
|
|
|
|
|
|
|
|
108
|
2
|
50
|
|
|
|
12
|
$logger -> debug( sprintf 'reference file read line transform sub reference was%s passed', |
109
|
|
|
|
|
|
|
defined $reference_file_read_line_transform_sub ? |
110
|
|
|
|
|
|
|
'' |
111
|
|
|
|
|
|
|
: ' not' |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
|
114
|
2
|
50
|
|
|
|
13
|
$self{reference_file_read_line_transform_sub} = $reference_file_read_line_transform_sub |
115
|
|
|
|
|
|
|
if defined $reference_file_read_line_transform_sub; |
116
|
|
|
|
|
|
|
|
117
|
2
|
50
|
66
|
|
|
8
|
$logger -> logdie( 'not valid reference file write line transform subroutine reference was passed as third argument' ) |
118
|
|
|
|
|
|
|
if defined $reference_file_write_line_transform_sub |
119
|
|
|
|
|
|
|
&& ref $reference_file_write_line_transform_sub ne 'CODE'; |
120
|
|
|
|
|
|
|
|
121
|
2
|
100
|
|
|
|
10
|
$logger -> debug( sprintf 'reference file write line transform sub reference was%s passed', |
122
|
|
|
|
|
|
|
defined $reference_file_write_line_transform_sub ? |
123
|
|
|
|
|
|
|
'' |
124
|
|
|
|
|
|
|
: ' not' |
125
|
|
|
|
|
|
|
); |
126
|
|
|
|
|
|
|
|
127
|
2
|
100
|
|
|
|
10
|
$self{reference_file_write_line_transform_sub} = $reference_file_write_line_transform_sub |
128
|
|
|
|
|
|
|
if defined $reference_file_write_line_transform_sub; |
129
|
|
|
|
|
|
|
|
130
|
2
|
100
|
|
|
|
4
|
if ( defined $line_joiner ) { |
131
|
1
|
50
|
|
|
|
5
|
$logger -> logdie( 'incorrect line joiner: ', $line_joiner ) |
132
|
|
|
|
|
|
|
unless grep $line_joiner eq $_, @line_joiner; |
133
|
|
|
|
|
|
|
|
134
|
1
|
|
|
|
|
2
|
$self{line_joiner} = $line_joiner; |
135
|
|
|
|
|
|
|
} else { |
136
|
1
|
|
|
|
|
4
|
$logger -> debug( 'line joiner undefined' ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
2
|
|
|
|
|
10
|
bless \ %self, $class; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _file_info { |
143
|
1
|
|
|
1
|
|
2
|
my $filename = shift; |
144
|
1
|
|
|
|
|
1
|
my $hashref = shift; |
145
|
|
|
|
|
|
|
|
146
|
1
|
|
|
|
|
3
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
147
|
|
|
|
|
|
|
|
148
|
1
|
|
|
|
|
14
|
$hashref -> {full_name} = $filename; |
149
|
|
|
|
|
|
|
# $hashref -> {name} = File::Basename::basename( $filename ); |
150
|
|
|
|
|
|
|
|
151
|
1
|
50
|
|
|
|
4
|
if ( -e Encode::encode( locale_fs => $filename ) ) { |
152
|
1
|
50
|
|
|
|
34
|
if ( -f _ ) { |
153
|
1
|
|
|
|
|
18
|
$hashref -> {size} = -s _; |
154
|
1
|
|
|
|
|
7
|
$hashref -> {mstat} = ( stat _ )[ 9 ]; |
155
|
|
|
|
|
|
|
} else { |
156
|
0
|
|
|
|
|
0
|
$logger -> warn( sprintf 'referenced file %s is not actually a file', |
157
|
|
|
|
|
|
|
$filename, |
158
|
|
|
|
|
|
|
); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} else { |
161
|
0
|
|
|
|
|
0
|
$logger -> warn( sprintf 'referenced file %s does not exist', |
162
|
|
|
|
|
|
|
$filename, |
163
|
|
|
|
|
|
|
); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 FILE READ/WRITE |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 read_existing_file |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Method for explicit reading of existing file. If file exists, this method has not been called and you're trying to update or write file it will be called implicitly before that. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Does not expect any arguments. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
If file exists and isn't empty it will be read and each line will be passed to the sub reference which was passed as second parameter to the constructor. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Returns itself for method chaining. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub read_existing_file { |
182
|
1
|
|
|
1
|
1
|
380
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
183
|
|
|
|
|
|
|
|
184
|
1
|
50
|
|
|
|
20
|
ref( my $self = shift ) or $logger -> logcroak( "I'm only an object method!" ); |
185
|
|
|
|
|
|
|
|
186
|
1
|
|
|
|
|
7
|
my $reference_file_fs = Encode::encode( locale_fs => $self -> {reference_file} ); |
187
|
|
|
|
|
|
|
|
188
|
1
|
50
|
|
|
|
119
|
if ( -e $reference_file_fs ) { |
189
|
|
|
|
|
|
|
$logger -> logdie( sprintf '% is not a file', |
190
|
|
|
|
|
|
|
$self -> {reference_file} |
191
|
|
|
|
|
|
|
) |
192
|
0
|
0
|
|
|
|
0
|
unless -f _; |
193
|
|
|
|
|
|
|
|
194
|
0
|
0
|
|
|
|
0
|
if ( -s _ ) { # non empty file |
195
|
|
|
|
|
|
|
$logger -> logdie( 'reference file exists, but reference file read line transform subroutine reference needed for reading its content was not provided to constructor' ) |
196
|
0
|
0
|
|
|
|
0
|
unless exists $self -> {reference_file_read_line_transform_sub}; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
$logger -> logdie( sprintf 'reference file %s is not readable', |
199
|
|
|
|
|
|
|
$self -> {reference_file}, |
200
|
|
|
|
|
|
|
) |
201
|
0
|
0
|
|
|
|
0
|
unless -r _; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
open my $fh, '<', $reference_file_fs |
204
|
|
|
|
|
|
|
or $logger -> logdie( sprintf 'cannot open file %s for reading: %s', |
205
|
|
|
|
|
|
|
$self -> {reference_file}, |
206
|
0
|
0
|
|
|
|
0
|
$!, |
207
|
|
|
|
|
|
|
); |
208
|
0
|
|
|
|
|
0
|
binmode $fh; |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
my $read_result = read $fh, ( my $t ), -s _; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
$logger -> logdie( sprintf 'reading from %s failed: %s', |
213
|
|
|
|
|
|
|
$self -> {reference_file}, |
214
|
0
|
0
|
|
|
|
0
|
$!, |
215
|
|
|
|
|
|
|
) |
216
|
|
|
|
|
|
|
unless defined $read_result; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
$logger -> logdie( sprintf 'errors while reading %s: expected to read %d bytes, but read %d', |
219
|
|
|
|
|
|
|
$self -> {reference_file}, |
220
|
0
|
0
|
|
|
|
0
|
-s _, |
221
|
|
|
|
|
|
|
$read_result, |
222
|
|
|
|
|
|
|
) |
223
|
|
|
|
|
|
|
unless $read_result == -s _; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
$self -> {line_joiner} = $line_joiner[ 1 ] |
226
|
|
|
|
|
|
|
unless exists $self -> {line_joiner} |
227
|
0
|
0
|
0
|
|
|
0
|
|| -1 == index $t, $line_joiner[ 1 ]; |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
0
|
for my $l ( split /\x0d?\x0a/, $t ) { # Reference files consist of a number of lines (terminated by 0x0a or 0x0d,0x0a) each consisting of the name of the file to transfer to the remote system. |
230
|
0
|
|
|
|
|
0
|
$logger -> debug( sprintf 'read octet line from reference file: %s', |
231
|
|
|
|
|
|
|
$l, |
232
|
|
|
|
|
|
|
); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
my %referenced_file = ( octet_line_in_reference_file => $l, |
235
|
0
|
|
|
|
|
0
|
character_line_in_reference_file => $self -> {reference_file_read_line_transform_sub} -> ( $l ), |
236
|
|
|
|
|
|
|
); |
237
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
0
|
my $full_name = $referenced_file{character_line_in_reference_file}; |
239
|
0
|
0
|
|
|
|
0
|
$referenced_file{prefix} = $1 |
240
|
|
|
|
|
|
|
if $full_name =~ s/^($prefix_re)//; # fts-5005.002 |
241
|
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
0
|
_file_info( $full_name, \ %referenced_file ); |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
0
|
push @{ $self -> {referenced_files} }, |
|
0
|
|
|
|
|
0
|
|
245
|
|
|
|
|
|
|
\ %referenced_file; |
246
|
|
|
|
|
|
|
} |
247
|
0
|
|
|
|
|
0
|
close $fh; |
248
|
|
|
|
|
|
|
} else { # file is empty |
249
|
0
|
|
|
|
|
0
|
$self -> {referenced_files} = []; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} else { # file does not exist |
252
|
1
|
|
|
|
|
7
|
$self -> {referenced_files} = []; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
1
|
|
|
|
|
5
|
$self; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 write_file |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Method for writing content from memory to the file. Does not need any parameters. |
261
|
|
|
|
|
|
|
If file exists and its content in memory is empty, it will be deleted. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Returns itself for method chaining. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=cut |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub write_file { |
268
|
1
|
|
|
1
|
1
|
10
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
269
|
|
|
|
|
|
|
|
270
|
1
|
50
|
|
|
|
35
|
ref( my $self = shift ) or $logger -> logcroak( "I'm only an object method!" ); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
$self -> read_existing_file |
273
|
1
|
50
|
|
|
|
4
|
unless exists $self -> {referenced_files}; |
274
|
|
|
|
|
|
|
|
275
|
1
|
|
|
|
|
4
|
my $reference_file_fs = Encode::encode( locale_fs => $self -> {reference_file} ); |
276
|
|
|
|
|
|
|
|
277
|
1
|
50
|
|
|
|
32
|
if ( @{ $self -> {referenced_files} } ) { # update the file |
|
1
|
0
|
|
|
|
4
|
|
278
|
|
|
|
|
|
|
# simple overwriting for now. later try File::Temp for new file and then File::Copy::move for moving over existing one |
279
|
|
|
|
|
|
|
my $line_joiner = exists $self -> {line_joiner} ? |
280
|
|
|
|
|
|
|
$self -> {line_joiner} |
281
|
1
|
50
|
|
|
|
5
|
: $line_joiner[ 0 ]; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
open my $fh, '>', $reference_file_fs |
284
|
|
|
|
|
|
|
or $logger -> logdie( sprintf 'cannot open %s: %s', |
285
|
|
|
|
|
|
|
$self -> {reference_file}, |
286
|
1
|
50
|
|
|
|
77
|
$!, |
287
|
|
|
|
|
|
|
); |
288
|
|
|
|
|
|
|
|
289
|
1
|
|
|
|
|
4
|
binmode $fh; |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
print $fh join $line_joiner, |
292
|
|
|
|
|
|
|
map $_ -> {octet_line_in_reference_file}, |
293
|
1
|
|
|
|
|
3
|
@{ $self -> {referenced_files} }; |
|
1
|
|
|
|
|
16
|
|
294
|
|
|
|
|
|
|
|
295
|
1
|
|
|
|
|
45
|
close $fh; |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
} elsif ( -e $reference_file_fs ) { # remove the file as it's empty |
298
|
0
|
|
|
|
|
0
|
$logger -> debug( 'removing empty ', $self -> {reference_file} ); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
unlink $self -> {reference_file} |
301
|
|
|
|
|
|
|
or $logger -> logdie( sprintf 'could not unlink %s: %s', |
302
|
|
|
|
|
|
|
$self -> {reference_file}, |
303
|
0
|
0
|
|
|
|
0
|
$!, |
304
|
|
|
|
|
|
|
); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
1
|
|
|
|
|
4
|
$self; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head1 CONTENT ACCESS |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 referenced_files |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Returns list of hash references describing referenced files in list content. |
315
|
|
|
|
|
|
|
In scalar content returns array reference. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Each hash has fields: |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
octet_line_in_reference_file - original line from the file or result returned by third parameter (sub reference) for constructor during push_reference method call. This is the value that will be written by write_file method call |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
character_line_in_reference_file - line that was returned by second parameter (sub reference) for constructor during existing file read or possibly prefixed second argument for push_reference |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
full_name - character line without prefix |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
There might be other fields: |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
prefix - if there is one |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
size - size in bytes if file existed during read_existing_file or push_reference method call |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
mstat - last modify time in seconds since the epoch if file existed during read_existing_file or push_reference method call |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=cut |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub referenced_files { |
336
|
1
|
|
|
1
|
1
|
356
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
337
|
|
|
|
|
|
|
|
338
|
1
|
50
|
|
|
|
27
|
ref( my $self = shift ) or $logger -> logcroak( "I'm only an object method!" ); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
$self -> read_existing_file |
341
|
1
|
50
|
|
|
|
4
|
unless exists $self -> {referenced_files}; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
wantarray ? |
344
|
1
|
|
|
|
|
4
|
@{ $self -> {referenced_files} } |
345
|
1
|
50
|
|
|
|
3
|
: $self -> {referenced_files}; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head1 CONTENT MODIFICATION |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 process_lines |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Method expects one parameter - function reference. That function will be called for each line in reference file with one parameter - hash reference with all details about the referenced file. |
353
|
|
|
|
|
|
|
Function can change/update fields - they are actual values, not a copy. |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Function return value is very important. |
356
|
|
|
|
|
|
|
If it is false then this line will be removed from the memory and after write_file call from the actual file. |
357
|
|
|
|
|
|
|
If return value is true then line stays. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
Method returns number of lines removed. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=cut |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub process_lines { |
364
|
0
|
|
|
0
|
1
|
0
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
365
|
|
|
|
|
|
|
|
366
|
0
|
0
|
|
|
|
0
|
ref( my $self = shift ) or $logger -> logcroak( "I'm only an object method!" ); |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
0
|
my $sub_ref = shift; # gets line hash ref and should return boolean (keep the line or not) |
369
|
|
|
|
|
|
|
|
370
|
0
|
0
|
0
|
|
|
0
|
$logger -> logdie( 'not valid condition subroutine reference was passed' ) |
371
|
|
|
|
|
|
|
unless defined $sub_ref |
372
|
|
|
|
|
|
|
&& ref $sub_ref eq 'CODE'; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
$self -> read_existing_file |
375
|
0
|
0
|
|
|
|
0
|
unless exists $self -> {referenced_files}; |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
my @idx_to_remove = grep ! $sub_ref -> ( $self -> {referenced_files}[ $_ ] ), |
378
|
0
|
|
|
|
|
0
|
0 .. $#{ $self -> {referenced_files} }; |
|
0
|
|
|
|
|
0
|
|
379
|
|
|
|
|
|
|
|
380
|
0
|
|
|
|
|
0
|
for ( reverse @idx_to_remove ) { |
381
|
|
|
|
|
|
|
$logger -> info( sprintf 'remove %s from %s', |
382
|
|
|
|
|
|
|
$self -> {referenced_files}[ $_ ]{full_name}, |
383
|
|
|
|
|
|
|
$self -> {reference_file}, |
384
|
0
|
|
|
|
|
0
|
); |
385
|
0
|
|
|
|
|
0
|
splice @{ $self -> {referenced_files} }, $_, 1; |
|
0
|
|
|
|
|
0
|
|
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
0
|
scalar @idx_to_remove; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head2 push_reference |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Expects referenced filename as a character string. If prefix [-#^~!@] needed, it should be defined as first parameter and filename as second parameter. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Returns itself for method chaining. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=cut |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub push_reference { |
400
|
1
|
|
|
1
|
1
|
10
|
my $logger = Log::Log4perl -> get_logger( __PACKAGE__ ); |
401
|
|
|
|
|
|
|
|
402
|
1
|
50
|
|
|
|
18
|
ref( my $self = shift ) or $logger -> logcroak( "I'm only an object method!" ); |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
$logger -> logdie( 'reference file write line transform subroutine reference needed for update was not passed to constructor' ) |
405
|
1
|
50
|
|
|
|
9
|
unless exists $self -> {reference_file_write_line_transform_sub}; |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
$self -> read_existing_file |
408
|
1
|
50
|
|
|
|
4
|
unless exists $self -> {referenced_files}; |
409
|
|
|
|
|
|
|
|
410
|
1
|
50
|
|
|
|
3
|
my ( $prefix, $filename ) = ( @_ == 1 ? undef : (), |
411
|
|
|
|
|
|
|
@_, |
412
|
|
|
|
|
|
|
); |
413
|
|
|
|
|
|
|
|
414
|
1
|
50
|
33
|
|
|
10
|
$logger -> logdie( 'Incorrect prefix: ' . $prefix ) |
415
|
|
|
|
|
|
|
if defined $prefix |
416
|
|
|
|
|
|
|
&& $prefix !~ m/$prefix_re/; |
417
|
|
|
|
|
|
|
|
418
|
1
|
|
|
|
|
2
|
my %new; |
419
|
|
|
|
|
|
|
|
420
|
1
|
|
|
|
|
3
|
_file_info( $filename, \ %new ); |
421
|
|
|
|
|
|
|
|
422
|
1
|
50
|
|
|
|
3
|
if ( defined $prefix ) { |
423
|
1
|
|
|
|
|
2
|
$new{prefix} = $prefix; |
424
|
1
|
|
|
|
|
3
|
$new{character_line_in_reference_file} = $prefix . $filename; |
425
|
|
|
|
|
|
|
} else { |
426
|
0
|
|
|
|
|
0
|
$new{character_line_in_reference_file} = $filename; |
427
|
|
|
|
|
|
|
} |
428
|
1
|
|
|
|
|
4
|
$new{octet_line_in_reference_file} = $self -> {reference_file_write_line_transform_sub} -> ( $new{character_line_in_reference_file} ); |
429
|
|
|
|
|
|
|
|
430
|
1
|
|
|
|
|
2295
|
push @{ $self -> {referenced_files} }, |
|
1
|
|
|
|
|
4
|
|
431
|
|
|
|
|
|
|
\ %new; |
432
|
|
|
|
|
|
|
|
433
|
1
|
|
|
|
|
5
|
$self; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
1; |