line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Smoke::Patcher; |
2
|
3
|
|
|
3
|
|
247960
|
use strict; |
|
3
|
|
|
|
|
10
|
|
|
3
|
|
|
|
|
126
|
|
3
|
|
|
|
|
|
|
|
4
|
3
|
|
|
3
|
|
19
|
use vars qw( $VERSION @EXPORT ); |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
222
|
|
5
|
|
|
|
|
|
|
$VERSION = '0.012'; |
6
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
34
|
use base 'Exporter'; |
|
3
|
|
|
|
|
13
|
|
|
3
|
|
|
|
|
430
|
|
8
|
3
|
|
|
3
|
|
25
|
use File::Spec; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
90
|
|
9
|
3
|
|
|
3
|
|
39
|
use Cwd; |
|
3
|
|
|
|
|
18
|
|
|
3
|
|
|
|
|
333
|
|
10
|
|
|
|
|
|
|
|
11
|
3
|
|
|
3
|
|
29
|
use Test::Smoke::Util qw( get_regen_headers ); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
9177
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
@EXPORT = qw( &TRY_REGEN_HEADERS ); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub MAX_FLAG_COUNT () { 16 } |
16
|
|
|
|
|
|
|
sub ALL_FLAGS () { (2**MAX_FLAG_COUNT) - 1 } |
17
|
|
|
|
|
|
|
sub TRY_REGEN_HEADERS () { 1 } |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my %CONFIG = ( |
20
|
|
|
|
|
|
|
df_ddir => File::Spec->rel2abs( cwd ), |
21
|
|
|
|
|
|
|
df_fdir => undef, |
22
|
|
|
|
|
|
|
df_pfile => undef, |
23
|
|
|
|
|
|
|
df_patchbin => 'patch', |
24
|
|
|
|
|
|
|
df_popts => '', # '-p1' is added in call_patch() |
25
|
|
|
|
|
|
|
df_flags => 0, |
26
|
|
|
|
|
|
|
df_regen => 1, # regen => set/unset TRY_REGEN_HEADERS in flags |
27
|
|
|
|
|
|
|
df_oldpatch => 0, |
28
|
|
|
|
|
|
|
df_v => 0, |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
valid_type => { single => 1, multi => 1 }, |
31
|
|
|
|
|
|
|
single => [qw( pfile patchbin popts flags regen oldpatch )], |
32
|
|
|
|
|
|
|
multi => [qw( pfile patchbin popts flags regen oldpatch )], |
33
|
|
|
|
|
|
|
); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 NAME |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Test::Smoke::Patcher - OO interface to help patching the source-tree |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 SYNOPSIS |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
use Test::Smoke::Patcher; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my $patcher = Test::Smoke::Patcher->new( single => { |
44
|
|
|
|
|
|
|
ddir => $build_dir, |
45
|
|
|
|
|
|
|
pfile => $patch, |
46
|
|
|
|
|
|
|
popts => '-p1', |
47
|
|
|
|
|
|
|
v => 1, # 0..2 |
48
|
|
|
|
|
|
|
}); |
49
|
|
|
|
|
|
|
$patcher->patch; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
or |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $patcher = Test::Smoke::Patcher->new( multi => { |
54
|
|
|
|
|
|
|
ddir => $buildir, |
55
|
|
|
|
|
|
|
pfile => $patch_info, |
56
|
|
|
|
|
|
|
v => 1, #0..2 |
57
|
|
|
|
|
|
|
}); |
58
|
|
|
|
|
|
|
$patcher->patch; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 DESCRIPTION |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Okay, you will need a working B program, which I believe is available |
63
|
|
|
|
|
|
|
for most platforms perl runs on. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
There are two ways to initialise the B object. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=over 4 |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=item B mode |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
The B attribute is a pointer to a I patch. |
72
|
|
|
|
|
|
|
There are four (4) ways to specify that patch. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=over 4 |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=item I |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
The scalar holds the complete patch as literal text. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item I |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
The array holds a list of lines (with newlines) that make up the |
83
|
|
|
|
|
|
|
patch as literal text (C<< $patch = join "", @$array_ref >>). |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item I |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
You passed an opened filehandle to a file containing the patch. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item I |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
If none of the above apply, it is assumed you passed a filename. |
92
|
|
|
|
|
|
|
Relative paths are rooted at the builddir (B attribute). |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=back |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=item B mode |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
The B attribute is a pointer to a recource that contains filenames |
99
|
|
|
|
|
|
|
of patches. |
100
|
|
|
|
|
|
|
The format of this recource is one filename per line optionally followed |
101
|
|
|
|
|
|
|
by a semi-colon (;) and switches for the patch program. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
The patch-resource can also be specified in four (4) ways. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=over 4 |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=item I |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item I |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item I |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item I |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=back |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=back |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head2 TRY_REGEN_HEADERS |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Constant: 1 |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head2 MAX_FLAG_COUNT |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Constant: 16 |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=head2 ALL_FLAGS |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Constant: 2**MAX_FLAG_COUNT) - 1 |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head1 METHODS |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=over 4 |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=cut |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=item Test::Smoke::Patcher->new( $type => \%args ); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
C crates the object. Valid types are B and B. |
140
|
|
|
|
|
|
|
Valid keys for C<%args>: |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
* ddir: the build directory |
143
|
|
|
|
|
|
|
* fdir: the intermediate forest dir (preferred) |
144
|
|
|
|
|
|
|
* pfile: path to either the patch (single) or a textfile (multi) |
145
|
|
|
|
|
|
|
* popts: options to pass to 'patch' (-p1) |
146
|
|
|
|
|
|
|
* patchbin: full path to the patch binary (patch) |
147
|
|
|
|
|
|
|
* regen: flag to set/unset the TRY_REGEN_HEADERS flag |
148
|
|
|
|
|
|
|
* v: verbosity 0..2 |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=cut |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub new { |
153
|
14
|
|
|
14
|
1
|
12424
|
my $proto = shift; |
154
|
14
|
|
33
|
|
|
220
|
my $class = ref $proto || $proto; |
155
|
|
|
|
|
|
|
|
156
|
14
|
|
|
|
|
75
|
my $type = lc shift; |
157
|
14
|
50
|
33
|
|
|
228
|
unless ( $type && exists $CONFIG{valid_type}->{ $type } ) { |
158
|
0
|
0
|
|
|
|
0
|
defined $type or $type = 'undef'; |
159
|
0
|
|
|
|
|
0
|
require Carp; |
160
|
0
|
|
|
|
|
0
|
Carp::croak( "Invalid Patcher-type: '$type'" ); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
14
|
50
|
|
|
|
136
|
my %args_raw = @_ ? UNIVERSAL::isa( $_[0], 'HASH' ) ? %{ $_[0] } : @_ : (); |
|
14
|
50
|
|
|
|
207
|
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
my %args = map { |
166
|
14
|
|
|
|
|
119
|
( my $key = $_ ) =~ s/^-?(.+)$/lc $1/e; |
|
52
|
|
|
|
|
489
|
|
|
52
|
|
|
|
|
250
|
|
167
|
52
|
|
|
|
|
309
|
( $key => $args_raw{ $_ } ); |
168
|
|
|
|
|
|
|
} keys %args_raw; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
my %fields = map { |
171
|
126
|
100
|
|
|
|
440
|
my $value = exists $args{$_} ? $args{ $_ } : $CONFIG{ "df_$_" }; |
172
|
126
|
|
|
|
|
579
|
( $_ => $value ) |
173
|
14
|
|
|
|
|
78
|
} ( v => ddir => fdir => @{ $CONFIG{ $type } } ); |
|
14
|
|
|
|
|
96
|
|
174
|
|
|
|
|
|
|
$fields{pdir} = File::Spec->rel2abs( |
175
|
|
|
|
|
|
|
defined $fields{fdir} ? $fields{fdir} : $fields{ddir} |
176
|
14
|
100
|
|
|
|
736
|
); |
177
|
14
|
|
|
|
|
54
|
$fields{ptype} = $type; |
178
|
14
|
50
|
|
|
|
42
|
if ($fields{regen}) { |
179
|
14
|
|
|
|
|
63
|
$fields{flags} = ($fields{flags} | TRY_REGEN_HEADERS) & ALL_FLAGS; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
else { |
182
|
0
|
|
|
|
|
0
|
$fields{flags} = ($fields{flags} & ~TRY_REGEN_HEADERS) & ALL_FLAGS; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
14
|
|
|
|
|
273
|
bless { %fields }, $class; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=item Test::Smoke::Patcher->config( $key[, $value] ) |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
C is an interface to the package lexical C<%CONFIG>, |
191
|
|
|
|
|
|
|
which holds all the default values for the C arguments. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
With the special key B this returns a reference |
194
|
|
|
|
|
|
|
to a hash holding all the default values. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub config { |
199
|
2
|
|
|
2
|
1
|
4934
|
my $dummy = shift; |
200
|
|
|
|
|
|
|
|
201
|
2
|
|
|
|
|
24
|
my $key = lc shift; |
202
|
|
|
|
|
|
|
|
203
|
2
|
100
|
|
|
|
14
|
if ( $key eq 'all_defaults' ) { |
204
|
|
|
|
|
|
|
my %default = map { |
205
|
1
|
|
|
|
|
14
|
my( $pass_key ) = $_ =~ /^df_(.+)/; |
|
9
|
|
|
|
|
26
|
|
206
|
9
|
|
|
|
|
36
|
( $pass_key => $CONFIG{ $_ } ); |
207
|
|
|
|
|
|
|
} grep /^df_/ => keys %CONFIG; |
208
|
1
|
|
|
|
|
6
|
return \%default; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
1
|
50
|
|
|
|
43
|
return undef unless exists $CONFIG{ "df_$key" }; |
212
|
|
|
|
|
|
|
|
213
|
1
|
50
|
|
|
|
26
|
$CONFIG{ "df_$key" } = shift if @_; |
214
|
|
|
|
|
|
|
|
215
|
1
|
|
|
|
|
13
|
return $CONFIG{ "df_$key" }; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=item $patcher->patch |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
C is a simple dispatcher. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub patch { |
225
|
10
|
|
|
10
|
1
|
890
|
my $self = shift; |
226
|
|
|
|
|
|
|
|
227
|
10
|
|
|
|
|
55
|
my $method = "patch_$self->{ptype}"; |
228
|
10
|
|
|
|
|
95
|
my $ret = $self->$method( @_ ); |
229
|
10
|
|
33
|
|
|
293
|
$ret &&= $self->perl_regen_headers; |
230
|
|
|
|
|
|
|
|
231
|
10
|
100
|
|
|
|
65
|
if ( $self->{fdir} ) { # This is a forest setup, re-sync |
232
|
1
|
|
|
|
|
11
|
require Test::Smoke::Syncer; |
233
|
|
|
|
|
|
|
my %options = ( |
234
|
|
|
|
|
|
|
hdir => $self->{fdir}, |
235
|
|
|
|
|
|
|
ddir => $self->{ddir}, |
236
|
|
|
|
|
|
|
v => $self->{v}, |
237
|
1
|
|
|
|
|
30
|
); |
238
|
1
|
|
|
|
|
41
|
my $resync = Test::Smoke::Syncer->new( hardlink => %options ); |
239
|
1
|
|
|
|
|
22
|
$resync->sync; |
240
|
|
|
|
|
|
|
} |
241
|
10
|
|
|
|
|
120
|
return $ret; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item perl_regen_headers( ) |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Try to run F if the flag is set. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=cut |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub perl_regen_headers { |
251
|
10
|
|
|
10
|
1
|
54
|
my $self = shift; |
252
|
10
|
50
|
|
|
|
97
|
return 1 unless $self->{flags} & TRY_REGEN_HEADERS; |
253
|
|
|
|
|
|
|
|
254
|
10
|
|
|
|
|
271
|
my $regen_headers = get_regen_headers( $self->{pdir} ); |
255
|
|
|
|
|
|
|
my $regen_perly = $self->{perly} |
256
|
10
|
100
|
|
|
|
134
|
? qq|$^X "| . File::Spec->catfile( $self->{pdir}, 'regen_perly.pl' ). |
257
|
|
|
|
|
|
|
qq|"| |
258
|
|
|
|
|
|
|
: ""; |
259
|
10
|
|
|
|
|
154
|
my @regens = grep $_ => ( $regen_headers, $regen_perly ); |
260
|
10
|
|
|
|
|
119
|
for my $regen ( @regens ) { |
261
|
2
|
|
|
|
|
9785
|
my $cwd = cwd; |
262
|
2
|
50
|
|
|
|
92
|
chdir $self->{pdir} or return; |
263
|
2
|
|
|
|
|
37
|
local *RUN_REGEN; |
264
|
2
|
50
|
|
|
|
7452
|
if ( open RUN_REGEN, "$regen |" ) { |
265
|
2
|
50
|
|
|
|
53
|
$self->{v} and print "Started [$regen]\n"; |
266
|
2
|
|
|
|
|
180837
|
while ( ) { |
267
|
0
|
0
|
|
|
|
0
|
$self->{v} and print; |
268
|
|
|
|
|
|
|
} |
269
|
2
|
50
|
|
|
|
138
|
close RUN_REGEN or do { |
270
|
0
|
|
|
|
|
0
|
require Carp; |
271
|
0
|
|
|
|
|
0
|
Carp::carp( "Error while running [$regen]" ); |
272
|
0
|
|
|
|
|
0
|
return; |
273
|
|
|
|
|
|
|
}; |
274
|
|
|
|
|
|
|
} else { |
275
|
0
|
|
|
|
|
0
|
require Carp; |
276
|
0
|
|
|
|
|
0
|
Carp::carp( "Could not fork [$regen]" ); |
277
|
0
|
|
|
|
|
0
|
return; |
278
|
|
|
|
|
|
|
} |
279
|
2
|
|
|
|
|
122
|
chdir $cwd; |
280
|
|
|
|
|
|
|
} |
281
|
10
|
|
|
|
|
187
|
return 1; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=item $patcher->patch_single( ) |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
C checks if the B attribute is a plain scalar |
287
|
|
|
|
|
|
|
or a ref to a scalar, array, glob. In the first case this is taken to |
288
|
|
|
|
|
|
|
be a filename. A GLOB-ref is a filehandle, the other two are taken to |
289
|
|
|
|
|
|
|
be literal content. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=cut |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub patch_single { |
294
|
22
|
|
|
22
|
1
|
34186
|
my $self = shift; |
295
|
|
|
|
|
|
|
|
296
|
22
|
|
66
|
|
|
289
|
my $pfile = shift || $self->{pfile}; |
297
|
|
|
|
|
|
|
|
298
|
22
|
|
|
|
|
123
|
local *PATCH; |
299
|
22
|
|
|
|
|
98
|
my $content; |
300
|
22
|
100
|
|
|
|
184
|
if ( ref $pfile eq 'SCALAR' ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
301
|
9
|
|
|
|
|
32
|
$content = $$pfile; |
302
|
9
|
|
50
|
|
|
100
|
$self->{pfinfo} ||= 'internal content'; |
303
|
|
|
|
|
|
|
} elsif ( ref $pfile eq 'ARRAY' ) { |
304
|
1
|
|
|
|
|
30
|
$content = join "", @$pfile; |
305
|
1
|
|
50
|
|
|
32
|
$self->{pfinfo} ||= 'internal content'; |
306
|
|
|
|
|
|
|
} elsif ( ref $pfile eq 'GLOB' ) { |
307
|
1
|
|
|
|
|
32
|
*PATCH = *$pfile; |
308
|
1
|
|
|
|
|
10
|
$content = do { local $/; }; |
|
1
|
|
|
|
|
23
|
|
|
1
|
|
|
|
|
69
|
|
309
|
1
|
|
50
|
|
|
22
|
$self->{pfinfo} ||= 'file content'; |
310
|
|
|
|
|
|
|
} else { |
311
|
|
|
|
|
|
|
my $full_name = File::Spec->file_name_is_absolute( $pfile ) |
312
|
11
|
50
|
|
|
|
424
|
? $pfile : File::Spec->rel2abs( $pfile, $self->{pdir} ); |
313
|
|
|
|
|
|
|
|
314
|
11
|
|
|
|
|
60
|
$self->{pfinfo} = $full_name; |
315
|
11
|
50
|
|
|
|
515
|
open PATCH, "< $full_name" or do { |
316
|
0
|
|
|
|
|
0
|
require Carp; |
317
|
0
|
|
|
|
|
0
|
Carp::croak( "Cannot open '$full_name': $!" ); |
318
|
|
|
|
|
|
|
}; |
319
|
11
|
|
|
|
|
51
|
$content = do { local $/; }; |
|
11
|
|
|
|
|
137
|
|
|
11
|
|
|
|
|
403
|
|
320
|
11
|
|
|
|
|
164
|
close PATCH; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
22
|
50
|
|
|
|
108
|
$self->{v} and print "Get patch from $self->{pfinfo}\n"; |
324
|
22
|
|
|
|
|
121
|
$self->call_patch( \$content, @_ ); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=item $patcher->patch_multi( ) |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
C checks the B attribute is a plain scalar |
330
|
|
|
|
|
|
|
or a ref to a scalar, array, glob. In the first case this is taken to |
331
|
|
|
|
|
|
|
be a filename. A GLOB-ref is a filehandle, the other two are taken to |
332
|
|
|
|
|
|
|
be literal content. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub patch_multi { |
337
|
6
|
|
|
6
|
1
|
11266
|
my $self = shift; |
338
|
|
|
|
|
|
|
|
339
|
6
|
|
66
|
|
|
63
|
my $pfile = shift || $self->{pfile}; |
340
|
|
|
|
|
|
|
|
341
|
6
|
|
|
|
|
29
|
local *PATCHES; |
342
|
6
|
|
|
|
|
37
|
my @patches; |
343
|
6
|
100
|
|
|
|
110
|
if ( ref $pfile eq 'SCALAR' ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
344
|
1
|
|
|
|
|
8
|
@patches = split /\n/, $$pfile; |
345
|
1
|
|
50
|
|
|
30
|
$self->{pfinfo} ||= 'internal content'; |
346
|
|
|
|
|
|
|
} elsif ( ref $pfile eq 'ARRAY' ) { |
347
|
1
|
|
|
|
|
7
|
chomp( @patches = @$pfile ); |
348
|
1
|
|
50
|
|
|
11
|
$self->{pfinfo} ||= 'internal content'; |
349
|
|
|
|
|
|
|
} elsif ( ref $pfile eq 'GLOB' ) { |
350
|
1
|
|
|
|
|
28
|
*PATCHES = *$pfile; |
351
|
1
|
|
|
|
|
74
|
chomp( @patches = ); |
352
|
1
|
|
50
|
|
|
20
|
$self->{pfinfo} ||= 'file content'; |
353
|
|
|
|
|
|
|
} else { |
354
|
|
|
|
|
|
|
my $full_name = File::Spec->file_name_is_absolute( $pfile ) |
355
|
3
|
50
|
|
|
|
89
|
? $pfile : File::Spec->rel2abs( $pfile, $self->{pdir} ); |
356
|
3
|
|
|
|
|
17
|
$self->{pfinfo} = $full_name; |
357
|
3
|
50
|
|
|
|
174
|
open PATCHES, "< $full_name" or do { |
358
|
0
|
|
|
|
|
0
|
require Carp; |
359
|
0
|
|
|
|
|
0
|
Carp::croak( "Cannot open '$self->{pfile}': $!" ); |
360
|
|
|
|
|
|
|
}; |
361
|
3
|
|
|
|
|
100
|
chomp( @patches = ); |
362
|
3
|
|
|
|
|
52
|
close PATCHES; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
6
|
50
|
|
|
|
36
|
$self->{v} and print "Get patchinfo from $self->{pfinfo}\n"; |
366
|
|
|
|
|
|
|
|
367
|
6
|
|
|
|
|
35
|
my $ok = 1; |
368
|
6
|
|
|
|
|
56
|
foreach my $patch ( @patches ) { |
369
|
17
|
100
|
|
|
|
178
|
next if $patch =~ /^\s*[#]/; |
370
|
10
|
50
|
|
|
|
78
|
next if $patch =~ /^\s*$/; |
371
|
10
|
100
|
|
|
|
84
|
if ( $patch =~ /^\s*!\s*perly$/ ) { |
372
|
1
|
|
|
|
|
14
|
$self->{perly} = 1; |
373
|
1
|
|
|
|
|
6
|
next; |
374
|
|
|
|
|
|
|
} |
375
|
9
|
|
|
|
|
118
|
my( $filename, $switches, $descr ) = split /\s*;\s*/, $patch, 3; |
376
|
9
|
50
|
|
|
|
40
|
$descr = $descr ? $descr . " ($filename)" : $filename; |
377
|
9
|
|
|
|
|
25
|
eval { $self->patch_single( $filename, $switches, $descr ) }; |
|
9
|
|
|
|
|
44
|
|
378
|
9
|
50
|
|
|
|
165
|
if ( $@ ) { |
379
|
0
|
|
|
|
|
0
|
require Carp; |
380
|
0
|
|
|
|
|
0
|
Carp::carp( "[$filename] $@" ); |
381
|
0
|
|
|
|
|
0
|
$ok = 0; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} |
384
|
6
|
|
|
|
|
85
|
return $ok; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=item $self->_make_opts( $switches ) |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
C<_make_opts()> just creates a string of options to pass to the |
390
|
|
|
|
|
|
|
B program. Some implementations of patch do not grog '-u', |
391
|
|
|
|
|
|
|
so be careful! |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=cut |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub _make_opts { |
396
|
23
|
|
|
23
|
|
4759
|
my $self = shift; |
397
|
23
|
|
|
|
|
135
|
@_ = grep defined $_ => @_; |
398
|
23
|
100
|
|
|
|
175
|
my $switches = @_ ? join " ", @_ : ""; |
399
|
|
|
|
|
|
|
|
400
|
23
|
|
100
|
|
|
335
|
my $opts = $switches || $self->{popts} || ""; |
401
|
23
|
100
|
|
|
|
122
|
$opts .= " -p1" unless $opts =~ /-[a-zA-Z]*p\d/; |
402
|
|
|
|
|
|
|
# $opts .= " -b" unless $opts =~ /-[a-zA-Z]*b/i; |
403
|
23
|
50
|
33
|
|
|
104
|
$opts .= " --verbose" if $self->{v} > 1 && !$self->{oldpatch}; |
404
|
|
|
|
|
|
|
|
405
|
23
|
|
|
|
|
92
|
return $opts; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=item $patcher->call_patch( $ref_to_content ) |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
C opens a pipe to the B program and prints |
411
|
|
|
|
|
|
|
C<< $$ref_to_content >> to it. It will Carp::croak() on any error! |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=cut |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub call_patch { |
416
|
22
|
|
|
22
|
1
|
88
|
my( $self, $ref_to_content, $switches, $descr ) = @_; |
417
|
|
|
|
|
|
|
|
418
|
22
|
|
|
|
|
79
|
local *PATCHBIN; |
419
|
|
|
|
|
|
|
|
420
|
22
|
|
|
|
|
134
|
my $opts = $self->_make_opts( $switches ); |
421
|
|
|
|
|
|
|
|
422
|
22
|
50
|
|
|
|
5564
|
my $redir = $self->{v} ? "" : ">" . File::Spec->devnull . " 2>&1"; |
423
|
|
|
|
|
|
|
|
424
|
22
|
|
|
|
|
109064
|
my $cwd = cwd(); |
425
|
22
|
50
|
|
|
|
764
|
chdir $self->{pdir} or do { |
426
|
0
|
|
|
|
|
0
|
require Carp; |
427
|
0
|
|
|
|
|
0
|
Carp::croak( "Cannot chdir($self->{pdir}): $!" ); |
428
|
|
|
|
|
|
|
}; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# patch is verbose enough if $self->{v} == 1 |
431
|
22
|
50
|
|
|
|
147
|
$self->{v} > 1 and |
432
|
|
|
|
|
|
|
print "[$self->{pfinfo}] | $self->{patchbin} $opts $redir\n"; |
433
|
|
|
|
|
|
|
|
434
|
22
|
50
|
|
|
|
91314
|
if ( open PATCHBIN, "| $self->{patchbin} $opts $redir" ) { |
435
|
22
|
|
|
|
|
296
|
binmode PATCHBIN; |
436
|
22
|
|
|
|
|
906
|
print PATCHBIN $$ref_to_content; |
437
|
22
|
50
|
|
|
|
87396
|
close PATCHBIN or do { |
438
|
0
|
|
|
|
|
0
|
require Carp; |
439
|
0
|
|
|
|
|
0
|
Carp::croak( "Error while patching from '$self->{pfinfo}': $!" ); |
440
|
|
|
|
|
|
|
}; |
441
|
|
|
|
|
|
|
} else { |
442
|
0
|
|
|
|
|
0
|
require Carp; |
443
|
0
|
|
|
|
|
0
|
Carp::croak( "Cannot fork ($self->{patchbin}): $!" ); |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# Add a line to patchlevel.h if $descr |
447
|
22
|
100
|
|
|
|
361
|
if ( defined $descr ) { |
448
|
10
|
|
|
|
|
425
|
require Test::Smoke::Util; |
449
|
10
|
|
|
|
|
359
|
Test::Smoke::Util::set_local_patch( $self->{pdir}, $descr ); |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
22
|
50
|
|
|
|
1638
|
chdir $cwd or do { |
453
|
0
|
|
|
|
|
|
require Carp; |
454
|
0
|
|
|
|
|
|
Carp::croak( "Cannot chdir($cwd) back: $!" ); |
455
|
|
|
|
|
|
|
}; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=back |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=head1 SEE ALSO |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
L, L |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head1 COPYRIGHT |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
(c) 2002-2003, All rights reserved. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
* Abe Timmerman |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
471
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
See: |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=over 4 |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=item * http://www.perl.com/perl/misc/Artistic.html |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=item * http://www.gnu.org/copyleft/gpl.html |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=back |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
484
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
485
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=cut |