line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Config::Model::Dpkg::Dependency ; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
307312
|
use 5.10.1; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
57
|
|
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
1213
|
use Mouse; |
|
1
|
|
|
|
|
35115
|
|
|
1
|
|
|
|
|
5
|
|
6
|
1
|
|
|
1
|
|
105613
|
use namespace::autoclean; |
|
1
|
|
|
|
|
26557
|
|
|
1
|
|
|
|
|
11
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Debian only module |
9
|
1
|
|
|
1
|
|
77
|
use lib '/usr/share/lintian/lib' ; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
10
|
1
|
|
|
1
|
|
705
|
use Lintian::Relation ; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use DB_File ; |
13
|
|
|
|
|
|
|
use Log::Log4perl qw(get_logger :levels); |
14
|
|
|
|
|
|
|
use Module::CoreList; |
15
|
|
|
|
|
|
|
use version ; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use Parse::RecDescent ; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
use AnyEvent::HTTP ; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# available only in debian. Black magic snatched from |
22
|
|
|
|
|
|
|
# /usr/share/doc/libapt-pkg-perl/examples/apt-version |
23
|
|
|
|
|
|
|
use AptPkg::Config '$_config'; |
24
|
|
|
|
|
|
|
use AptPkg::System '$_system'; |
25
|
|
|
|
|
|
|
use AptPkg::Version; |
26
|
|
|
|
|
|
|
use AptPkg::Cache ; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use vars qw/$test_filter/ ; |
29
|
|
|
|
|
|
|
$test_filter = ''; # reserved for tests |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $logger = get_logger("Tree::Element::Value::Dependency") ; |
32
|
|
|
|
|
|
|
my $async_log = get_logger("Async::Value::Dependency") ; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# initialise the global config object with the default values |
35
|
|
|
|
|
|
|
$_config->init; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# determine the appropriate system type |
38
|
|
|
|
|
|
|
$_system = $_config->system; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# fetch a versioning system |
41
|
|
|
|
|
|
|
my $vs = $_system->versioning; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my $apt_cache = AptPkg::Cache->new ; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# end black magic |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
extends qw/Config::Model::Value/ ; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# when apply_fix is used ($arg[1]), this grammer will modify inline |
50
|
|
|
|
|
|
|
# the dependency value through the value ref ($arg[2]) |
51
|
|
|
|
|
|
|
my $grammar = << 'EOG' ; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
{ |
54
|
|
|
|
|
|
|
my @dep_errors ; |
55
|
|
|
|
|
|
|
my $add_error = sub { |
56
|
|
|
|
|
|
|
my ($err, $txt) = @_ ; |
57
|
|
|
|
|
|
|
push @dep_errors, "$err: '$txt'" ; |
58
|
|
|
|
|
|
|
return ; # to ensure production error |
59
|
|
|
|
|
|
|
} ; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# comment this out when modifying the grammar |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
dependency: { @dep_errors = (); } |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
dependency: depend(s /\|/) eofile { |
68
|
|
|
|
|
|
|
$return = [ 1 , @{$item[1]} ] ; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
| { |
71
|
|
|
|
|
|
|
push( @dep_errors, "Cannot parse: '$text'" ) unless @dep_errors ; |
72
|
|
|
|
|
|
|
$return = [ 0, @dep_errors ]; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
depend: pkg_dep | variable |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# For the allowed stuff after ${foo}, see #702792 |
78
|
|
|
|
|
|
|
variable: /\${[\w:\-]+}[\w\.\-~+]*/ |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
pkg_dep: pkg_name dep_version(?) arch_restriction(?) { |
81
|
|
|
|
|
|
|
my $dv = $item[2] ; |
82
|
|
|
|
|
|
|
my $ar = $item[3] ; |
83
|
|
|
|
|
|
|
my @ret = ( $item{pkg_name} ) ; |
84
|
|
|
|
|
|
|
if (@$dv and @$ar) { push @ret, @{$dv->[0]}, @{$ar->[0]} ;} |
85
|
|
|
|
|
|
|
elsif (@$dv) { push @ret, @{$dv->[0]} ;} |
86
|
|
|
|
|
|
|
elsif (@$ar) { push @ret, undef, undef, @{$ar->[0]} ;} |
87
|
|
|
|
|
|
|
$return = \@ret ; ; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
arch_restriction: '[' osarch(s) ']' |
91
|
|
|
|
|
|
|
{ |
92
|
|
|
|
|
|
|
my $mismatch = 0; |
93
|
|
|
|
|
|
|
my $ref = $item[2] ; |
94
|
|
|
|
|
|
|
for (my $i = 0; $i < $#$ref -1 ; $i++ ) { |
95
|
|
|
|
|
|
|
$mismatch ||= ($ref->[$i][0] xor $ref->[$i+1][0]) ; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
my @a = map { ($_->[0] || '') . ($_->[1] || '') . $_->[2] } @$ref ; |
98
|
|
|
|
|
|
|
if ($mismatch) { |
99
|
|
|
|
|
|
|
$add_error->("some names are prepended with '!' while others aren't.", "@a") ; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
else { |
102
|
|
|
|
|
|
|
$return = \@a ; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
dep_version: '(' oper version ')' { $return = [ $item{oper}, $item{version} ] ;} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
pkg_name: /[a-z0-9][a-z0-9\+\-\.]+(?=\s|\Z|\(|\[)/ |
109
|
|
|
|
|
|
|
| /\S+/ { $add_error->("bad package name", $item[1]) ;} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
oper: '<<' | '<=' | '=' | '>=' | '>>' |
112
|
|
|
|
|
|
|
| /\S+/ { $add_error->("bad dependency version operator", $item[1]) ;} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
version: variable | /[\w\.\-~:+]+(?=\s|\)|\Z)/ |
115
|
|
|
|
|
|
|
| /\S+/ { $add_error->("bad dependency version", $item[1]) ;} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# valid arch are listed by dpkg-architecture -L |
118
|
|
|
|
|
|
|
osarch: not(?) os(?) arch |
119
|
|
|
|
|
|
|
{ |
120
|
|
|
|
|
|
|
$return = [ $item[1][0], $item[2][0], $item[3] ]; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
not: '!' |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
os: /(any|uclibc-linux|linux|kfreebsd|knetbsd|kopensolaris|hurd|darwin|freebsd|netbsd|openbsd|solaris|uclinux) |
126
|
|
|
|
|
|
|
-/x |
127
|
|
|
|
|
|
|
| /\w+/ '-' { $add_error->("bad os in architecture specification", $item[1]) ;} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
arch: / (any |alpha|amd64 |arm\b |arm64 |armeb |armel |armhf |avr32 |
130
|
|
|
|
|
|
|
|hppa |i386 |ia64 |lpia |m32r |m68k |mips\b |mipsel |powerpc |
131
|
|
|
|
|
|
|
|powerpcspe |ppc64 |s390 |s390x |sh3\b |sh3eb |sh4\b |sh4eb |sparc\b |sparc64 |x32 ) |
132
|
|
|
|
|
|
|
(?=(\]| )) |
133
|
|
|
|
|
|
|
/x |
134
|
|
|
|
|
|
|
| /\w+/ { $add_error->("bad arch in architecture specification", $item[1]) ;} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
eofile: /^\Z/ |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
EOG |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $parser ; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub dep_parser { |
144
|
|
|
|
|
|
|
$parser ||= Parse::RecDescent->new($grammar) ; |
145
|
|
|
|
|
|
|
return $parser ; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# this method may recurse bad: |
149
|
|
|
|
|
|
|
# check_dep -> meta filter -> control maintainer -> create control class |
150
|
|
|
|
|
|
|
# autoread started -> read all fileds -> read dependency -> check_dep ... |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub check_value { |
153
|
|
|
|
|
|
|
my $self = shift ; |
154
|
|
|
|
|
|
|
my %args = @_ > 1 ? @_ : (value => $_[0]) ; |
155
|
|
|
|
|
|
|
my $cb = delete $args{callback} || sub {} ; |
156
|
|
|
|
|
|
|
my $my_cb = sub { |
157
|
|
|
|
|
|
|
$self->check_dependency(@_, callback => $cb) ; |
158
|
|
|
|
|
|
|
} ; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
$args{fix} //= 0; |
161
|
|
|
|
|
|
|
$self->SUPER::check_value(%args, callback => $my_cb) ; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub check_dependency { |
166
|
|
|
|
|
|
|
my $self = shift; |
167
|
|
|
|
|
|
|
my %args = @_ ; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my ($value, $check, $silent, $notify_change, $ok, $callback,$apply_fix) |
170
|
|
|
|
|
|
|
= @args{qw/value check silent notify_change ok callback fix/} ; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# value is one dependency, something like "perl ( >= 1.508 )" |
173
|
|
|
|
|
|
|
# or exim | mail-transport-agent or gnumach-dev [hurd-i386] |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# see http://www.debian.org/doc/debian-policy/ch-relationships.html |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# to get package list |
178
|
|
|
|
|
|
|
# wget -q -O - 'http://qa.debian.org/cgi-bin/madison.cgi?package=perl-doc&text=on' |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
my @dep_chain ; |
181
|
|
|
|
|
|
|
if (defined $value) { |
182
|
|
|
|
|
|
|
$logger->debug("calling check_depend with Parse::RecDescent with '$value'"); |
183
|
|
|
|
|
|
|
my $ret = dep_parser->dependency ( $value ) ; |
184
|
|
|
|
|
|
|
my $ok = shift @$ret ; |
185
|
|
|
|
|
|
|
if ($ok) { |
186
|
|
|
|
|
|
|
@dep_chain = @$ret ; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
else { |
189
|
|
|
|
|
|
|
$self->add_error(@$ret) ; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# check_dependency is always called with a callback. This callback must |
194
|
|
|
|
|
|
|
# must called *after* all asynchronous calls are done (which depends on the |
195
|
|
|
|
|
|
|
# packages listed in the dependency). So use begin and end on this condvar and |
196
|
|
|
|
|
|
|
# nothing else, not send/recv |
197
|
|
|
|
|
|
|
my $pending_check = AnyEvent->condvar ; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
my $old = $value ; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $check_depend_chain_cb = sub { |
202
|
|
|
|
|
|
|
# blocking with inner async calls |
203
|
|
|
|
|
|
|
$self->check_depend_chain($apply_fix, \@dep_chain, $old ) ; |
204
|
|
|
|
|
|
|
$self->on_check_all_done($apply_fix,\@dep_chain,$old, sub { $callback->(%args) if $callback; }); |
205
|
|
|
|
|
|
|
} ; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
$async_log->debug("begin for ",$self->composite_name, " fix is $apply_fix") if $async_log->is_debug; |
208
|
|
|
|
|
|
|
$pending_check->begin($check_depend_chain_cb) ; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
foreach my $dep (@dep_chain) { |
211
|
|
|
|
|
|
|
next unless ref($dep) ; # no need to check variables |
212
|
|
|
|
|
|
|
$pending_check->begin ; |
213
|
|
|
|
|
|
|
my $cb = sub { |
214
|
|
|
|
|
|
|
$self->check_or_fix_essential_package($apply_fix, $dep, $old) ; # sync |
215
|
|
|
|
|
|
|
$self->check_or_fix_dep($apply_fix, $dep, $old, sub { $pending_check -> end}) ; # async |
216
|
|
|
|
|
|
|
}; |
217
|
|
|
|
|
|
|
$self->check_or_fix_pkg_name($apply_fix, $dep, $old, $cb) ; # async |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
$async_log->debug("end for ",$self->composite_name) if $async_log->is_debug; |
222
|
|
|
|
|
|
|
$pending_check->end; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# this callback will be launched when all checks are done. this can be at |
226
|
|
|
|
|
|
|
# the 'end' call at this end of this sub if all calls of check_depend are |
227
|
|
|
|
|
|
|
# synchronous (which may be the case if all dependency informations are in cache) |
228
|
|
|
|
|
|
|
# or it can be in one of the call backs |
229
|
|
|
|
|
|
|
sub on_check_all_done { |
230
|
|
|
|
|
|
|
my ($self, $apply_fix, $dep_chain, $old, $next) = @_ ; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# "ideal" dependency is always computed, but it does not always change |
233
|
|
|
|
|
|
|
my $new = $self->struct_to_dep(@$dep_chain); |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
if ( $logger->is_debug ) { |
236
|
|
|
|
|
|
|
my $new //= ''; |
237
|
|
|
|
|
|
|
$async_log->debug( "in on_check_all_done callback for ", |
238
|
|
|
|
|
|
|
$self->composite_name, " ($new) fix is $apply_fix" ) |
239
|
|
|
|
|
|
|
if $async_log->is_debug; |
240
|
|
|
|
|
|
|
no warnings 'uninitialized'; |
241
|
|
|
|
|
|
|
$logger->debug( "'$old' done" . ( $apply_fix ? " changed to '$new'" : '' ) ); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
{ |
245
|
|
|
|
|
|
|
no warnings 'uninitialized'; |
246
|
|
|
|
|
|
|
$self->_store_fix( $old, $new ) if $apply_fix and $new ne $old; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
$next->(); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub check_debhelper_version { |
252
|
|
|
|
|
|
|
my ($self, $apply_fix, $depend) = @_ ; |
253
|
|
|
|
|
|
|
my ( $dep_name, $oper, $dep_v, @archs ) = @$depend ; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
my $dep_string = $self->struct_to_dep($depend) ; |
256
|
|
|
|
|
|
|
my $lintian_dep = Lintian::Relation->new( $dep_string ) ; |
257
|
|
|
|
|
|
|
$logger->debug("checking '$dep_string' with lintian"); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# using mode loose because debian-control model can be used alone |
260
|
|
|
|
|
|
|
# and compat is outside of debian-control |
261
|
|
|
|
|
|
|
my $compat = $self->grab_value(mode => 'loose', step => "!Dpkg compat") ; |
262
|
|
|
|
|
|
|
return unless defined $compat ; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
my $min_dep = Lintian::Relation->new("debhelper ( >= $compat)") ; |
265
|
|
|
|
|
|
|
$logger->debug("checking if ".$lintian_dep->unparse." implies ". $min_dep->unparse); |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
return if $lintian_dep->implies ($min_dep) ; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
$logger->debug("'$dep_string' does not imply debhelper >= $compat"); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# $show_rel avoids undef warnings |
272
|
|
|
|
|
|
|
my $show_rel = join(' ', map { $_ || ''} ($oper, $dep_v)); |
273
|
|
|
|
|
|
|
if ($apply_fix) { |
274
|
|
|
|
|
|
|
@$depend = ( 'debhelper', '>=', $compat ) ; # notify_change called in check_value |
275
|
|
|
|
|
|
|
$logger->info("fixed debhelper dependency from " |
276
|
|
|
|
|
|
|
."$dep_name $show_rel -> ".$min_dep->unparse." (for compat $compat)"); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
else { |
279
|
|
|
|
|
|
|
$self->{nb_of_fixes}++ ; |
280
|
|
|
|
|
|
|
my $msg = "should be (>= $compat) not ($show_rel) because compat is $compat" ; |
281
|
|
|
|
|
|
|
$self->add_warning( $msg ); |
282
|
|
|
|
|
|
|
$logger->info("will warn: $msg (fix++)"); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
my @deb_releases = qw/etch lenny squeeze wheezy/; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
my %deb_release_h ; |
289
|
|
|
|
|
|
|
while (@deb_releases) { |
290
|
|
|
|
|
|
|
my $k = pop @deb_releases ; |
291
|
|
|
|
|
|
|
my $regexp = join('|',@deb_releases,$k); |
292
|
|
|
|
|
|
|
$deb_release_h{$k} = qr/$regexp/; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# called in check_versioned_dep and in Parse::RecDescent grammar |
296
|
|
|
|
|
|
|
sub xxget_pkg_versions { |
297
|
|
|
|
|
|
|
my ($self,$cb,$pkg) = @_ ; |
298
|
|
|
|
|
|
|
$logger->debug("get_pkg_versions: called with $pkg"); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# check if Debian has version older than required version |
301
|
|
|
|
|
|
|
my ($has_info, @dist_version) = $self->get_available_version($pkg) ; |
302
|
|
|
|
|
|
|
# print "\t'$pkg' => '@dist_version',\n"; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
return () unless $has_info ; |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
return @dist_version ; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# |
310
|
|
|
|
|
|
|
# New subroutine "struct_to_dep" extracted - Mon Aug 27 13:45:02 2012. |
311
|
|
|
|
|
|
|
# |
312
|
|
|
|
|
|
|
sub struct_to_dep { |
313
|
|
|
|
|
|
|
my $self = shift ; |
314
|
|
|
|
|
|
|
my @input = @_ ; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
my $skip = 0 ; |
317
|
|
|
|
|
|
|
my @alternatives ; |
318
|
|
|
|
|
|
|
foreach my $d (@input) { |
319
|
|
|
|
|
|
|
my $line = ''; |
320
|
|
|
|
|
|
|
# empty str or ref to empty array are skipped |
321
|
|
|
|
|
|
|
if( ref ($d) and @$d) { |
322
|
|
|
|
|
|
|
$line .= "$d->[0]"; |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# skip test for relations like << or < |
325
|
|
|
|
|
|
|
$skip ++ if defined $d->[1] and $d->[1] =~ / ; |
326
|
|
|
|
|
|
|
$line .= " ($d->[1] $d->[2])" if defined $d->[2]; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
if (@$d > 3) { |
329
|
|
|
|
|
|
|
$line .= ' ['. join(' ',@$d[3..$#$d]) .']' ; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
elsif (not ref($d) and $d) { |
334
|
|
|
|
|
|
|
$line .= $d ; |
335
|
|
|
|
|
|
|
} ; |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
push @alternatives, $line if $line ; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
my $actual_dep = @alternatives ? join (' | ',@alternatives) : undef ; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
return wantarray ? ($actual_dep, $skip) : $actual_dep ; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# @input contains the alternates dependencies (without '|') of one dependency values |
346
|
|
|
|
|
|
|
# a bit like @input = split /|/, $dependency |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# will modify @input (array of ref) when applying fix |
349
|
|
|
|
|
|
|
sub check_depend_chain { |
350
|
|
|
|
|
|
|
my ($self, $apply_fix, $input, $old) = @_ ; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
my ($actual_dep, $skip) = $self->struct_to_dep (@$input); |
353
|
|
|
|
|
|
|
my $ret = 1 ; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
return 1 unless defined $actual_dep; # may have been cleaned during fix |
356
|
|
|
|
|
|
|
$logger->debug("called with $actual_dep with apply_fix $apply_fix"); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
if ($skip) { |
359
|
|
|
|
|
|
|
$logger->debug("skipping '$actual_dep': has a < relation ship") ; |
360
|
|
|
|
|
|
|
return $ret ; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$async_log->debug("begin check alternate deps for $actual_dep") ; |
364
|
|
|
|
|
|
|
foreach my $depend (@$input) { |
365
|
|
|
|
|
|
|
if (ref ($depend)) { |
366
|
|
|
|
|
|
|
# is a dependency (not a variable a la ${perl-Depends}) |
367
|
|
|
|
|
|
|
my ($dep_name, $oper, $dep_v) = @$depend ; |
368
|
|
|
|
|
|
|
$logger->debug("scanning dependency $dep_name" |
369
|
|
|
|
|
|
|
.(defined $dep_v ? " $dep_v" : '')); |
370
|
|
|
|
|
|
|
if ($dep_name =~ /lib([\w+\-]+)-perl/) { |
371
|
|
|
|
|
|
|
my $pname = $1 ; |
372
|
|
|
|
|
|
|
# AnyEvent condvar is involved in this method, blocks while inner async call are in progress |
373
|
|
|
|
|
|
|
$ret &&= $self->check_perl_lib_dep ($apply_fix, $pname, $actual_dep, $depend,$input); |
374
|
|
|
|
|
|
|
last; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
$async_log->debug("end check alternate deps for $actual_dep") ; |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
if ($logger->is_debug and $apply_fix) { |
381
|
|
|
|
|
|
|
my $str = $self->struct_to_dep(@$input) ; |
382
|
|
|
|
|
|
|
$str //= '' ; |
383
|
|
|
|
|
|
|
$logger->debug("new dependency is $str"); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
return $ret ; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# called through check_depend_chain |
390
|
|
|
|
|
|
|
# does modify $input when applying fix |
391
|
|
|
|
|
|
|
sub check_perl_lib_dep { |
392
|
|
|
|
|
|
|
my ($self, $apply_fix, $pname, $actual_dep, $depend, $input) = @_; |
393
|
|
|
|
|
|
|
$logger->debug("called with $actual_dep with apply_fix $apply_fix"); |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my ( $dep_name, $oper, $dep_v ) = @$depend; |
396
|
|
|
|
|
|
|
my $ret = 1; |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
$pname =~ s/-/::/g; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# The dependency should be in the form perl (>= 5.10.1) | libtest-simple-perl (>= 0.88)". |
401
|
|
|
|
|
|
|
# cf http://pkg-perl.alioth.debian.org/policy.html#debian_control_handling |
402
|
|
|
|
|
|
|
# If the Perl version is not available in sid, the order of the dependency should be reversed |
403
|
|
|
|
|
|
|
# libcpan-meta-perl | perl (>= 5.13.10) |
404
|
|
|
|
|
|
|
# because buildd will use the first available alternative |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
# check for dual life module, module name follows debian convention... |
407
|
|
|
|
|
|
|
my @dep_name_as_perl = Module::CoreList->find_modules(qr/^$pname$/i) ; |
408
|
|
|
|
|
|
|
return $ret unless @dep_name_as_perl; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
return $ret if defined $dep_v && $dep_v =~ m/^\$/ ; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# here we have async consecutive calls to get_available_version, check_versioned_dep |
413
|
|
|
|
|
|
|
# and get_available_version. Must block and return once they are done |
414
|
|
|
|
|
|
|
# hence the condvar |
415
|
|
|
|
|
|
|
my $perl_dep_cv = AnyEvent->condvar ; |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
my @ideal_perl_dep = qw/perl/ ; |
418
|
|
|
|
|
|
|
my @ideal_lib_dep ; |
419
|
|
|
|
|
|
|
my @ideal_dep_chain = (\@ideal_perl_dep); |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
my ($on_get_lib_version, $on_perl_check_done, $check_perl_lib, $get_perl_versions, $on_get_perl_versions) ; |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
my ($v_normal) ; |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# check version for the first available version in Debian: debian |
426
|
|
|
|
|
|
|
# dep may have no version specified but older versions can be found |
427
|
|
|
|
|
|
|
# in CPAN that were never packaged in Debian |
428
|
|
|
|
|
|
|
$on_get_lib_version = sub { |
429
|
|
|
|
|
|
|
$async_log->debug("on_get_lib_version called with @_") ; |
430
|
|
|
|
|
|
|
# get_available_version returns oldest first, like (etch,1.2,...) |
431
|
|
|
|
|
|
|
my $oldest_lib_version_in_debian = $_[1] ; |
432
|
|
|
|
|
|
|
# lob off debian release number |
433
|
|
|
|
|
|
|
$oldest_lib_version_in_debian =~ s/-.*//; |
434
|
|
|
|
|
|
|
my $check_v = $dep_v || $oldest_lib_version_in_debian ; |
435
|
|
|
|
|
|
|
$logger->debug("dual life $dep_name has oldest debian $oldest_lib_version_in_debian, using $check_v"); |
436
|
|
|
|
|
|
|
my ($cpan_dep_v, $epoch_dep_v) ; |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
($cpan_dep_v, $epoch_dep_v) = reverse split /:/ ,$check_v if defined $check_v ; |
439
|
|
|
|
|
|
|
my $v_decimal = Module::CoreList->first_release( |
440
|
|
|
|
|
|
|
$dep_name_as_perl[0], |
441
|
|
|
|
|
|
|
version->parse( $cpan_dep_v ) |
442
|
|
|
|
|
|
|
); |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
if (defined $v_decimal) { |
445
|
|
|
|
|
|
|
$v_normal = version->new($v_decimal)->normal; |
446
|
|
|
|
|
|
|
$v_normal =~ s/^v//; # loose the v prefix |
447
|
|
|
|
|
|
|
if ( $logger->is_debug ) { |
448
|
|
|
|
|
|
|
my $dep_str = $dep_name . ( defined $check_v ? ' ' . $check_v : '' ); |
449
|
|
|
|
|
|
|
$logger->debug("dual life $dep_str aka $dep_name_as_perl[0] found in Perl core $v_normal"); |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
$self->check_versioned_dep( $on_perl_check_done , ['perl', '>=', $v_normal] ); |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
else { |
454
|
|
|
|
|
|
|
# no need to check further. Call send to unblock wait done with recv |
455
|
|
|
|
|
|
|
AnyEvent::postpone { $perl_dep_cv->send }; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
}; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
$on_perl_check_done = sub { |
461
|
|
|
|
|
|
|
my $has_older_perl = shift ; |
462
|
|
|
|
|
|
|
$async_log->debug("on_perl_check_done called") ; |
463
|
|
|
|
|
|
|
push @ideal_perl_dep, '>=', $v_normal if $has_older_perl; |
464
|
|
|
|
|
|
|
$check_perl_lib->($has_older_perl) ; |
465
|
|
|
|
|
|
|
} ; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
$check_perl_lib = sub { |
468
|
|
|
|
|
|
|
my $has_older_perl = shift; |
469
|
|
|
|
|
|
|
$async_log->debug( "check_perl_lib called with dep_v " . ( $dep_v // 'undef' ) ); |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
my $on_perl_lib_check_done = sub { |
472
|
|
|
|
|
|
|
my $has_older_lib = shift; |
473
|
|
|
|
|
|
|
$async_log->debug("on_perl_lib_check_done called"); |
474
|
|
|
|
|
|
|
if ($has_older_perl) { |
475
|
|
|
|
|
|
|
push @ideal_lib_dep, $dep_name; |
476
|
|
|
|
|
|
|
push @ideal_lib_dep, '>=', $dep_v if $has_older_lib; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
$get_perl_versions->(); |
479
|
|
|
|
|
|
|
}; |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
if ( defined $dep_v ) { |
482
|
|
|
|
|
|
|
$self->check_versioned_dep( $on_perl_lib_check_done, $depend ); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
else { |
485
|
|
|
|
|
|
|
$on_perl_lib_check_done->(0); |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
}; |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
$get_perl_versions = sub { |
490
|
|
|
|
|
|
|
$self->get_available_version($on_get_perl_versions, 'perl'); |
491
|
|
|
|
|
|
|
} ; |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$on_get_perl_versions = sub { |
494
|
|
|
|
|
|
|
my %perl_version = @_ ; |
495
|
|
|
|
|
|
|
$async_log->debug("running on_get_perl_versions for $actual_dep") ; |
496
|
|
|
|
|
|
|
my $has_older_perl_in_sid = ( $vs->compare( $v_normal, $perl_version{sid} ) < 0 ) ? 1 : 0; |
497
|
|
|
|
|
|
|
$logger->debug( |
498
|
|
|
|
|
|
|
"perl $v_normal is", |
499
|
|
|
|
|
|
|
$has_older_perl_in_sid ? ' ' : ' not ', |
500
|
|
|
|
|
|
|
"older than perl in sid ($perl_version{sid})" |
501
|
|
|
|
|
|
|
); |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
my @ordered_ideal_dep = $has_older_perl_in_sid ? |
504
|
|
|
|
|
|
|
( \@ideal_perl_dep, \@ideal_lib_dep ) : |
505
|
|
|
|
|
|
|
( \@ideal_lib_dep, \@ideal_perl_dep ) ; |
506
|
|
|
|
|
|
|
my $ideal_dep = $self->struct_to_dep( @ordered_ideal_dep ); |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
if ( $actual_dep ne $ideal_dep ) { |
509
|
|
|
|
|
|
|
if ($apply_fix) { |
510
|
|
|
|
|
|
|
@$input = @ordered_ideal_dep ; # notify_change called in check_value |
511
|
|
|
|
|
|
|
$logger->info("fixed dependency with: $ideal_dep, was @$depend"); |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
else { |
514
|
|
|
|
|
|
|
$self->{nb_of_fixes}++; |
515
|
|
|
|
|
|
|
my $msg = "Dependency of dual life package should be '$ideal_dep' not '$actual_dep'"; |
516
|
|
|
|
|
|
|
$self->add_warning ($msg); |
517
|
|
|
|
|
|
|
$logger->info("will warn: $msg (fix++)"); |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
$ret = 0; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
$perl_dep_cv->send ; |
522
|
|
|
|
|
|
|
} ; |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
# start the whole async stuff |
525
|
|
|
|
|
|
|
$self->get_available_version($on_get_lib_version, $dep_name); |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
$async_log->debug("waiting for $actual_dep") ; |
529
|
|
|
|
|
|
|
$perl_dep_cv->recv ; |
530
|
|
|
|
|
|
|
$async_log->debug("waiting done for $actual_dep") ; |
531
|
|
|
|
|
|
|
return $ret ; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub check_versioned_dep { |
535
|
|
|
|
|
|
|
my ($self, $callback ,$dep_info) = @_ ; |
536
|
|
|
|
|
|
|
my ( $pkg, $oper, $vers ) = @$dep_info; |
537
|
|
|
|
|
|
|
$logger->debug("called with '" . $self->struct_to_dep($dep_info) ."'") if $logger->is_debug; |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# special case to keep lintian happy |
540
|
|
|
|
|
|
|
$callback->(1) if $pkg eq 'debhelper' ; |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
my $cb = sub { |
543
|
|
|
|
|
|
|
my @dist_version = @_ ; |
544
|
|
|
|
|
|
|
$async_log->debug("in check_versioned_dep callback with ". $self->struct_to_dep($dep_info) |
545
|
|
|
|
|
|
|
." -> @dist_version") if $async_log->is_debug; |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
if ( @dist_version # no older for unknow packages |
548
|
|
|
|
|
|
|
and defined $oper |
549
|
|
|
|
|
|
|
and $oper =~ />/ |
550
|
|
|
|
|
|
|
and $vers !~ /^\$/ # a dpkg variable |
551
|
|
|
|
|
|
|
) { |
552
|
|
|
|
|
|
|
my $src_pkg_name = $self->grab_value("!Dpkg::Control source Source") ; |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
my $filter = $test_filter || $self->grab_value( |
555
|
|
|
|
|
|
|
step => qq{!Dpkg my_config package-dependency-filter:"$src_pkg_name"}, |
556
|
|
|
|
|
|
|
mode => 'loose', |
557
|
|
|
|
|
|
|
) || ''; |
558
|
|
|
|
|
|
|
$callback->($self->has_older_version_than ($pkg, $vers, $filter, \@dist_version )); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
else { |
561
|
|
|
|
|
|
|
$callback->(1) ; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
}; |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# check if Debian has version older than required version |
566
|
|
|
|
|
|
|
$self->get_available_version($cb, $pkg) ; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
sub has_older_version_than { |
571
|
|
|
|
|
|
|
my ($self, $pkg, $vers, $filter, $dist_version ) = @_; |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
$logger->debug("using filter $filter") if $filter; |
574
|
|
|
|
|
|
|
my $regexp = $deb_release_h{$filter} ; |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
$logger->debug("using regexp $regexp") if defined $regexp; |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
my @list ; |
579
|
|
|
|
|
|
|
my $has_older = 0; |
580
|
|
|
|
|
|
|
while (@$dist_version) { |
581
|
|
|
|
|
|
|
my ($d,$v) = splice @$dist_version,0,2 ; |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
next if defined $regexp and $d =~ $regexp ; |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
push @list, "$d -> $v;" ; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
if ($vs->compare($vers,$v) > 0 ) { |
588
|
|
|
|
|
|
|
$has_older = 1 ; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
$logger->debug("$pkg $vers has_older is $has_older (@list)"); |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
return 1 if $has_older ; |
595
|
|
|
|
|
|
|
return wantarray ? (0,@list) : 0 ; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# |
599
|
|
|
|
|
|
|
# New subroutine "check_essential_package" extracted - Thu Aug 30 14:14:32 2012. |
600
|
|
|
|
|
|
|
# |
601
|
|
|
|
|
|
|
sub check_or_fix_essential_package { |
602
|
|
|
|
|
|
|
my ( $self, $apply_fix, $dep_info ) = @_; |
603
|
|
|
|
|
|
|
my ( $pkg, $oper, $vers ) = @$dep_info; |
604
|
|
|
|
|
|
|
$logger->debug("called with '", scalar $self->struct_to_dep($dep_info), "' and fix $apply_fix") if $logger->is_debug; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# Remove unversioned dependency on essential package (Debian bug 684208) |
607
|
|
|
|
|
|
|
# see /usr/share/doc/libapt-pkg-perl/examples/apt-cache |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
my $cache_item = $apt_cache->get($pkg); |
610
|
|
|
|
|
|
|
my $is_essential = 0; |
611
|
|
|
|
|
|
|
$is_essential++ if (defined $cache_item and $cache_item->get('Flags') =~ /essential/i); |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
if ($is_essential and not defined $oper) { |
614
|
|
|
|
|
|
|
$logger->debug( "found unversioned dependency on essential package: $pkg"); |
615
|
|
|
|
|
|
|
if ($apply_fix) { |
616
|
|
|
|
|
|
|
@$dep_info = (); |
617
|
|
|
|
|
|
|
$logger->info("fix: removed unversioned essential dependency on $pkg"); |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
else { |
620
|
|
|
|
|
|
|
my $msg = "unnecessary unversioned dependency on essential package: $pkg"; |
621
|
|
|
|
|
|
|
$self->add_warning($msg); |
622
|
|
|
|
|
|
|
$self->{nb_of_fixes}++; |
623
|
|
|
|
|
|
|
$logger->info("will warn: $msg (fix++)"); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
my %pkg_replace = ( |
630
|
|
|
|
|
|
|
'perl-module' => 'perl' , |
631
|
|
|
|
|
|
|
) ; |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub check_or_fix_pkg_name { |
634
|
|
|
|
|
|
|
my ( $self, $apply_fix, $dep_info, $old, $next ) = @_; |
635
|
|
|
|
|
|
|
my ( $pkg, $oper, $vers ) = @$dep_info; |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
$logger->debug("called with '", scalar $self->struct_to_dep($dep_info), "' and fix $apply_fix") |
638
|
|
|
|
|
|
|
if $logger->is_debug; |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
my $new = $pkg_replace{$pkg} ; |
641
|
|
|
|
|
|
|
if ( $new ) { |
642
|
|
|
|
|
|
|
if ($apply_fix) { |
643
|
|
|
|
|
|
|
$logger->info("fix: changed package name from $pkg to $new"); |
644
|
|
|
|
|
|
|
$dep_info->[0] = $pkg = $new; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
else { |
647
|
|
|
|
|
|
|
my $msg = "dubious package name: $pkg. Preferred package is $new"; |
648
|
|
|
|
|
|
|
$self-> add_warning ($msg); |
649
|
|
|
|
|
|
|
$self->{nb_of_fixes}++; |
650
|
|
|
|
|
|
|
$logger->info("will warn: $msg (fix++)"); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
# check if this package is defined in current control file |
655
|
|
|
|
|
|
|
if ($self->grab(step => "- - binary:$pkg", qw/mode loose autoadd 0/)) { |
656
|
|
|
|
|
|
|
$logger->debug("dependency $pkg provided in control file") ; |
657
|
|
|
|
|
|
|
$next->() ; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
else { |
660
|
|
|
|
|
|
|
my $cb = sub { |
661
|
|
|
|
|
|
|
if ( @_ == 0 ) { |
662
|
|
|
|
|
|
|
# no version found for $pkg |
663
|
|
|
|
|
|
|
# don't know how to distinguish virtual package from source package |
664
|
|
|
|
|
|
|
$logger->debug("unknown package $pkg"); |
665
|
|
|
|
|
|
|
$self->add_warning( |
666
|
|
|
|
|
|
|
"package $pkg is unknown. Check for typos if not a virtual package."); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
$async_log->debug("callback for check_or_fix_pkg_name -> end for $pkg"); |
669
|
|
|
|
|
|
|
$next->( ); |
670
|
|
|
|
|
|
|
}; |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# is asynchronous |
673
|
|
|
|
|
|
|
$async_log->debug("begin on $pkg"); |
674
|
|
|
|
|
|
|
$self->get_available_version( $cb, $pkg ); |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
# if no pkg was found |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
# all subs but one there are synchronous |
681
|
|
|
|
|
|
|
sub check_or_fix_dep { |
682
|
|
|
|
|
|
|
my ( $self, $apply_fix, $dep_info, $old, $next ) = @_; |
683
|
|
|
|
|
|
|
my ( $pkg, $oper, $vers, @archs ) = @$dep_info; |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
$logger->debug("called with '", scalar $self->struct_to_dep($dep_info), "' and fix $apply_fix") |
686
|
|
|
|
|
|
|
if $logger->is_debug; |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
if(not defined $pkg) { |
689
|
|
|
|
|
|
|
# pkg may be cleaned up during fix |
690
|
|
|
|
|
|
|
$next->() ; |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
elsif ( $pkg eq 'debhelper' ) { |
693
|
|
|
|
|
|
|
$self->check_debhelper_version( $apply_fix, $dep_info ); |
694
|
|
|
|
|
|
|
$next->() ; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
else { |
697
|
|
|
|
|
|
|
my $cb = sub { |
698
|
|
|
|
|
|
|
my ( $vers_dep_ok, @list ) = @_ ; |
699
|
|
|
|
|
|
|
$async_log->debug("callback for check_or_fix_dep with @_") ; |
700
|
|
|
|
|
|
|
$self->warn_or_remove_vers_dep ($apply_fix, $dep_info, \@list) unless $vers_dep_ok ; |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
$async_log->debug("callback for check_or_fix_dep -> end") ; |
703
|
|
|
|
|
|
|
$next->() ; |
704
|
|
|
|
|
|
|
} ; |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
$async_log->debug("begin") ; |
707
|
|
|
|
|
|
|
$self->check_versioned_dep($cb, $dep_info ); |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
} |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub warn_or_remove_vers_dep { |
713
|
|
|
|
|
|
|
my ( $self, $apply_fix, $dep_info, $list ) = @_; |
714
|
|
|
|
|
|
|
my ( $pkg, $oper, $vers ) = @$dep_info; |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
if ($apply_fix) { |
717
|
|
|
|
|
|
|
splice @$dep_info, 1, 2; # remove versioned dep, notify_change called in check_value |
718
|
|
|
|
|
|
|
$logger->info("fix: removed versioned dependency from @$dep_info -> $pkg"); |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
else { |
721
|
|
|
|
|
|
|
$self->{nb_of_fixes}++; |
722
|
|
|
|
|
|
|
my $msg = "unnecessary versioned dependency: @$dep_info. Debian has @$list"; |
723
|
|
|
|
|
|
|
$self->add_warning( $msg); |
724
|
|
|
|
|
|
|
$logger->info("will warn: $msg (fix++)"); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
use vars qw/%cache/ ; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# Set up persistence |
731
|
|
|
|
|
|
|
my $cache_file_name = $ENV{HOME}.'/.config_model_depend_cache' ; |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
# this condition is used during tests |
734
|
|
|
|
|
|
|
if (not %cache) { |
735
|
|
|
|
|
|
|
tie %cache => 'DB_File', $cache_file_name, |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# required to write data back to DB_File |
739
|
|
|
|
|
|
|
END { |
740
|
|
|
|
|
|
|
untie %cache ; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
my %requested ; |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
sub push_cb { |
746
|
|
|
|
|
|
|
my $pkg = shift; |
747
|
|
|
|
|
|
|
my $ref = $requested{$pkg} ||= [] ; |
748
|
|
|
|
|
|
|
push @$ref, @_ ; |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
sub call_cbs { |
752
|
|
|
|
|
|
|
my $pkg = shift; |
753
|
|
|
|
|
|
|
return unless $requested{$pkg} ; |
754
|
|
|
|
|
|
|
my $ref = delete $requested{$pkg} ; |
755
|
|
|
|
|
|
|
map { $_->(@_) } @$ref ; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# asynchronous method |
760
|
|
|
|
|
|
|
sub get_available_version { |
761
|
|
|
|
|
|
|
my ($self, $callback,$pkg_name) = @_ ; |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
$async_log->debug("called on $pkg_name"); |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
my ($time,@res) = split / /, ($cache{$pkg_name} || ''); |
766
|
|
|
|
|
|
|
if (defined $time and $time =~ /^\d+$/ and $time + 24 * 60 * 60 * 7 > time) { |
767
|
|
|
|
|
|
|
$async_log->debug("using cached info for $pkg_name"); |
768
|
|
|
|
|
|
|
$callback->(@res) ; |
769
|
|
|
|
|
|
|
return; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# package info was requested but info is still not there |
773
|
|
|
|
|
|
|
# this may be called twice for the same package: one for source, one |
774
|
|
|
|
|
|
|
# for binary package |
775
|
|
|
|
|
|
|
if ($requested{$pkg_name}){ |
776
|
|
|
|
|
|
|
push_cb($pkg_name,$callback) ; |
777
|
|
|
|
|
|
|
return ; |
778
|
|
|
|
|
|
|
} ; |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
my $url = "http://qa.debian.org/cgi-bin/madison.cgi?package=$pkg_name&text=on" ; |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
push_cb($pkg_name,$callback); |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
say "Connecting to qa.debian.org to check $pkg_name versions. Please wait..." ; |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
my $request; |
787
|
|
|
|
|
|
|
$request = http_request( |
788
|
|
|
|
|
|
|
GET => $url, |
789
|
|
|
|
|
|
|
timeout => 20, # seconds |
790
|
|
|
|
|
|
|
sub { |
791
|
|
|
|
|
|
|
my ($body, $hdr) = @_; |
792
|
|
|
|
|
|
|
$async_log->debug("callback of get_available_version called on $pkg_name"); |
793
|
|
|
|
|
|
|
if ($hdr->{Status} =~ /^2/) { |
794
|
|
|
|
|
|
|
my @res ; |
795
|
|
|
|
|
|
|
foreach my $line (split /\n/, $body) { |
796
|
|
|
|
|
|
|
my ($name,$available_v,$dist,$type) = split /\s*\|\s*/, $line ; |
797
|
|
|
|
|
|
|
$type =~ s/\s//g ; |
798
|
|
|
|
|
|
|
push @res , $dist, $available_v unless $type eq 'source'; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
say "got info for $pkg_name" ; |
801
|
|
|
|
|
|
|
$cache{$pkg_name} = time ." @res" ; |
802
|
|
|
|
|
|
|
call_cbs($pkg_name,@res) ; |
803
|
|
|
|
|
|
|
} |
804
|
|
|
|
|
|
|
else { |
805
|
|
|
|
|
|
|
say "Error for $url: ($hdr->{Status}) $hdr->{Reason}"; |
806
|
|
|
|
|
|
|
delete $requested{$pkg_name} ; # trash the callbacks |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
undef $request; |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
); |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
1; |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=head1 NAME |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
Config::Model::Dpkg::Dependency - Checks Debian dependency declarations |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=head1 SYNOPSIS |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
use Config::Model ; |
824
|
|
|
|
|
|
|
use Log::Log4perl qw(:easy) ; |
825
|
|
|
|
|
|
|
use Data::Dumper ; |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Log::Log4perl->easy_init($WARN); |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
# define configuration tree object |
830
|
|
|
|
|
|
|
my $model = Config::Model->new ; |
831
|
|
|
|
|
|
|
$model ->create_config_class ( |
832
|
|
|
|
|
|
|
name => "MyClass", |
833
|
|
|
|
|
|
|
element => [ |
834
|
|
|
|
|
|
|
Depends => { |
835
|
|
|
|
|
|
|
'type' => 'leaf', |
836
|
|
|
|
|
|
|
'value_type' => 'uniline', |
837
|
|
|
|
|
|
|
class => 'Config::Model::Dpkg::Dependency', |
838
|
|
|
|
|
|
|
}, |
839
|
|
|
|
|
|
|
], |
840
|
|
|
|
|
|
|
) ; |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
my $inst = $model->instance(root_class_name => 'MyClass' ); |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
my $root = $inst->config_root ; |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
$root->load( 'Depends="libc6 ( >= 1.0 )"') ; |
847
|
|
|
|
|
|
|
# Connecting to qa.debian.org to check libc6 versions. Please wait ... |
848
|
|
|
|
|
|
|
# Warning in 'Depends' value 'libc6 ( >= 1.0 )': unnecessary |
849
|
|
|
|
|
|
|
# versioned dependency: >= 1.0. Debian has lenny-security -> |
850
|
|
|
|
|
|
|
# 2.7-18lenny6; lenny -> 2.7-18lenny7; squeeze-security -> |
851
|
|
|
|
|
|
|
# 2.11.2-6+squeeze1; squeeze -> 2.11.2-10; wheezy -> 2.11.2-10; sid |
852
|
|
|
|
|
|
|
# -> 2.11.2-10; sid -> 2.11.2-11; |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=head1 DESCRIPTION |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
This class is derived from L. Its purpose is to |
857
|
|
|
|
|
|
|
check the value of a Debian package dependency for the following: |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=over |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
=item * |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
syntax as described in http://www.debian.org/doc/debian-policy/ch-relationships.html |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
=item * |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
Whether the version specified with C<< > >> or C<< >= >> is necessary. |
868
|
|
|
|
|
|
|
This module will check with Debian server whether older versions can be |
869
|
|
|
|
|
|
|
found in Debian old-stable or not. If no older version can be found, a |
870
|
|
|
|
|
|
|
warning will be issued. Note a warning will also be sent if the package |
871
|
|
|
|
|
|
|
is not found on madison and if the package is not virtual. |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=item * |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
Whether a Perl library is dual life. In this case the dependency is checked according to |
876
|
|
|
|
|
|
|
L. |
877
|
|
|
|
|
|
|
Because Debian auto-build systems (buildd) will use the first available alternative, |
878
|
|
|
|
|
|
|
the dependency should be in the form : |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
=over |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=item * |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
C<< perl (>= 5.10.1) | libtest-simple-perl (>= 0.88) >> when |
885
|
|
|
|
|
|
|
the required perl version is available in sid. ". |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=item * |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
C<< libcpan-meta-perl | perl (>= 5.13.10) >> when the Perl version is not available in sid |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=back |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
=back |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
=head1 Cache |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
Queries to Debian server are cached in C<~/.config_model_depend_cache> |
898
|
|
|
|
|
|
|
for about one month. |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=head1 BUGS |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=over |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=item * |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
Virtual package names are found scanning local apt cache. Hence an unknown package |
907
|
|
|
|
|
|
|
on your system may a virtual package on another system. |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
=item * |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
More advanced checks can probably be implemented. The author is open to |
912
|
|
|
|
|
|
|
new ideas. He's even more open to patches (with tests). |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=back |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=head1 AUTHOR |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
Dominique Dumont, ddumont [AT] cpan [DOT] org |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=head1 SEE ALSO |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
L, |
923
|
|
|
|
|
|
|
L, |
924
|
|
|
|
|
|
|
L, |
925
|
|
|
|
|
|
|
L |