110
60
($progname = $0) =~ s,.*/,,;
111
62
if ($prognames{$progname}) {
112
$conf->set('DB_OPERATION', $prognames{$progname});
114
elsif ($progname =~ /^list-(.*)$/) {
63
$conf->set('DB_OPERATION', $prognames{$progname});
64
} elsif ($progname =~ /^list-(.*)$/) {
115
65
$conf->set('DB_OPERATION', 'list');
116
66
$conf->set('DB_LIST_STATE', ($1 eq "all") ? "" : $1);
119
$conf->set('DB_OPERATION', $conf->get('DB_CATEGORY') ? "set-failed" : "set-building")
120
if !$conf->get('DB_OPERATION'); # default operation
121
$conf->set('DB_LIST_ORDER', $conf->get('DB_LIST_STATE') eq "failed" ? 'fPcpasn' : 'PScpasn')
122
if (!$conf->get('DB_LIST_ORDER') &&
123
(defined($conf->get('DB_LIST_STATE')) && $conf->get('DB_LIST_STATE')));
124
$conf->set('DISTRIBUTION', 'unstable')
125
if !defined($conf->get('DISTRIBUTION'));
127
die "Bad distribution '" . $conf->get('DISTRIBUTION') . "'\n"
128
if !isin($conf->get('DISTRIBUTION'), keys %{$conf->get('DB_DISTRIBUTIONS')});
130
if ($conf->get('VERBOSE')) {
131
print "wanna-build (Debian sbuild) $Sbuild::Sysconfig::version ($Sbuild::Sysconfig::release_date) on " . $conf->get('HOSTNAME') . "\n";
132
print "Using database " . $conf->get('DB_BASE_NAME') . '/' . $conf->get('DISTRIBUTION') . "\n"
135
if (!@ARGV && !isin( $conf->get('DB_OPERATION'), qw(list merge-quinn merge-partial-quinn import export
136
merge-packages manual-edit maintlock-create
137
merge-sources maintlock-remove clean-db))) {
138
usage_error("wanna-build", "No packages given.");
141
if (!$conf->get('DB_FAIL_REASON')) {
142
if ($conf->get('DB_OPERATION') eq "set-failed" && !$conf->get('DB_CATEGORY')) {
143
print "Enter reason for failing (end with '.' alone on ".
149
last if $line eq ".\n";
150
$line = ".\n" if $line eq "\n";
154
$conf->set('DB_FAIL_REASON', $log);
155
} elsif ($conf->get('DB_OPERATION') eq "set-dep-wait") {
156
print "Enter dependencies (one line):\n";
158
while( !$line && !eof(STDIN) ) {
159
chomp( $line = <STDIN> );
161
die "No dependencies given\n" if !$line;
162
$conf->set('DB_FAIL_REASON'. $line);
163
} elsif ($conf->get('DB_OPERATION') eq "set-binary-nmu" and $conf->get('DB_BIN_NMU_VERSION') > 0) {
164
print "Enter changelog entry (one line):\n";
166
while( !$line && !eof(STDIN) ) {
167
chomp( $line = <STDIN> );
169
die "No changelog entry given\n" if !$line;
170
$conf->set('DB_FAIL_REASON', $line);
173
if ($conf->get('DB_OPERATION') eq "maintlock-create") {
177
if ($conf->get('DB_OPERATION') eq "maintlock-remove") {
181
waitfor_maintlock() if $conf->get('DB_OPERATION') !~ /^(?:merge-|clean-db$)/;
183
if (!-f db_filename( $conf->get('DISTRIBUTION') ) && !$conf->get('DB_CREATE')) {
184
die "Database for " . $conf->get('DISTRIBUTION') . " doesn't exist\n";
69
# All logging is to standard out and error; no log stream to set.
70
my $status = $database->run();
188
foreach (keys %databases) {
189
$databases{$_}->close();
190
undef $databases{$_};
194
# TODO: Use %databases only.
195
$db = open_db($conf->get('DISTRIBUTION'));
200
defined($conf->get('DB_LOG_MAIL')) && $conf->get('DB_LOG_MAIL')) {
201
send_mail( $conf->get('DB_LOG_MAIL'),
202
"wanna-build " . $conf->get('DISTRIBUTION') .
203
" state changes $curr_date",
204
"State changes at $curr_date for distribution ".
205
$conf->get('DISTRIBUTION') . ":\n\n$mail_logs\n" );
213
SWITCH: foreach ($conf->get('DB_OPERATION')) {
215
add_packages( $1, @ARGV );
219
list_packages($conf->get('DB_LIST_STATE'));
223
info_packages( @ARGV );
226
/^forget-user/ && do {
227
die "This operation is restricted to admin users\n"
228
if (defined @{$conf->get('DB_ADMIN_USERS')} and
229
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
230
forget_users( @ARGV );
234
forget_packages( @ARGV );
237
/^merge-partial-quinn/ && do {
238
die "This operation is restricted to admin users\n"
239
if (defined @{$conf->get('DB_ADMIN_USERS')} and
240
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
244
/^merge-quinn/ && do {
245
die "This operation is restricted to admin users\n"
246
if (defined @{$conf->get('DB_ADMIN_USERS')} and
247
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
251
/^merge-packages/ && do {
252
die "This operation is restricted to admin users\n"
253
if (defined @{$conf->get('DB_ADMIN_USERS')} and
254
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
258
/^merge-sources/ && do {
259
die "This operation is restricted to admin users\n"
260
if (defined @{$conf->get('DB_ADMIN_USERS')} and
261
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
265
/^pretend-avail/ && do {
266
pretend_avail( @ARGV );
270
die "This operation is restricted to admin users\n"
271
if (defined @{$conf->get('DB_ADMIN_USERS')} and
272
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
274
@ARGV = ( $ARGS[0] );
275
my $pkgs = parse_packages();
276
@ARGV = ( $ARGS[1] );
278
@ARGV = ( $ARGS[2] );
279
my $build_deps = parse_sources(1);
280
auto_dep_wait( $build_deps, $pkgs );
285
die "This operation is restricted to admin users\n"
286
if (defined @{$conf->get('DB_ADMIN_USERS')} and
287
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
288
$db->clear(); # clear all current contents
289
$db->restore($conf->get('DB_IMPORT_FILE'));
293
$db->dump($conf->get('DB_EXPORT_FILE'));
296
/^manual-edit/ && do {
297
die "This operation is restricted to admin users\n"
298
if (defined @{$conf->get('DB_ADMIN_USERS')} and
299
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
300
my $tmpfile_pattern = "/tmp/wanna-build-" . $conf->get('DISTRIBUTION') . ".$$-";
302
for( $i = 0;; ++$i ) {
303
$tmpfile = $tmpfile_pattern . $i;
304
last if ! -e $tmpfile;
307
my $editor = $ENV{'VISUAL'} ||
308
"/usr/bin/sensible-editor";
309
system "$editor $tmpfile";
310
$db->clear(); # clear all current contents
311
$db->restore($tmpfile);
316
die "This operation is restricted to admin users\n"
317
if (defined @{$conf->get('DB_ADMIN_USERS')} and
318
!isin( $conf->get('USERNAME'), @{$conf->get('DB_ADMIN_USERS')}));
323
die "Unexpected operation mode " . $conf->get('DB_OPERATION') . "\n";
325
if (not -t and $conf->get('DB_USER') =~ /-/) {
326
my $ui = $db->get_user($conf->get('DB_USER'));
327
$ui = {} if (!defined($ui));
329
$ui->{'Last-Seen'} = $curr_date;
330
$ui->{'User'} = $conf->get('DB_USER');
337
sub add_packages ($@) {
338
my $newstate = shift;
339
my( $package, $name, $version, $ok, $reason );
341
foreach $package (@_) {
342
$package =~ s,^.*/,,; # strip path
343
$package =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
344
$package =~ s/_[a-zA-Z\d-]+\.changes$//; # strip extension
345
if ($package =~ /^([\w\d.+-]+)_([\w\d:.+~-]+)/) {
346
($name,$version) = ($1,$2);
349
warn "$package: can't extract package name and version ".
354
if ($conf->get('DB_OPERATION') eq "set-building") {
355
add_one_building( $name, $version );
357
elsif ($conf->get('DB_OPERATION') eq "set-built") {
358
add_one_built( $name, $version );
360
elsif ($conf->get('DB_OPERATION') eq "set-attempted") {
361
add_one_attempted( $name, $version );
363
elsif ($conf->get('DB_OPERATION') eq "set-uploaded") {
364
add_one_uploaded( $name, $version );
366
elsif ($conf->get('DB_OPERATION') eq "set-failed") {
367
add_one_failed( $name, $version );
369
elsif ($conf->get('DB_OPERATION') eq "set-not-for-us") {
370
add_one_notforus( $name, $version );
372
elsif ($conf->get('DB_OPERATION') eq "set-needs-build") {
373
add_one_needsbuild( $name, $version );
375
elsif ($conf->get('DB_OPERATION') eq "set-dep-wait") {
376
add_one_depwait( $name, $version );
378
elsif ($conf->get('DB_OPERATION') eq "set-build-priority") {
379
set_one_buildpri( $name, $version, 'BuildPri' );
381
elsif ($conf->get('DB_OPERATION') eq "set-permanent-build-priority") {
382
set_one_buildpri( $name, $version, 'PermBuildPri' );
384
elsif ($conf->get('DB_OPERATION') eq "set-binary-nmu") {
385
set_one_binnmu( $name, $version );
390
sub add_one_building ($$) {
396
my $pkg = $db->get_package($name);
398
if ($pkg->{'State'} eq "Not-For-Us") {
400
$reason = "not suitable for this architecture";
402
elsif ($pkg->{'State'} =~ /^Dep-Wait/) {
404
$reason = "not all source dependencies available yet";
406
elsif ($pkg->{'State'} eq "Uploaded" &&
407
(version_lesseq($version, $pkg->{'Version'}))) {
409
$reason = "already uploaded by $pkg->{'Builder'}";
410
$reason .= " (in newer version $pkg->{'Version'})"
411
if !version_eq($pkg, $version);
413
elsif ($pkg->{'State'} eq "Installed" &&
414
version_less($version,$pkg->{'Version'})) {
415
if ($conf->get('DB_OVERRIDE')) {
416
print "$name: Warning: newer version $pkg->{'Version'} ".
417
"already installed, but overridden.\n";
421
$reason = "newer version $pkg->{'Version'} already in ".
422
"archive; doesn't need rebuilding";
423
print "$name: Note: If the following is due to an epoch ",
424
" change, use --override\n";
427
elsif ($pkg->{'State'} eq "Installed" &&
428
pkg_version_eq($pkg,$version)) {
430
$reason = "is up-to-date in the archive; doesn't need rebuilding";
432
elsif ($pkg->{'State'} eq "Needs-Build" &&
433
version_less($version,$pkg->{'Version'})) {
434
if ($conf->get('DB_OVERRIDE')) {
435
print "$name: Warning: newer version $pkg->{'Version'} ".
436
"needs building, but overridden.";
440
$reason = "newer version $pkg->{'Version'} needs building, ".
444
elsif (isin($pkg->{'State'},qw(Building Built Build-Attempted))) {
445
if (version_less($pkg->{'Version'},$version)) {
446
print "$name: Warning: Older version $pkg->{'Version'} ",
447
"is being built by $pkg->{'Builder'}\n";
448
if ($pkg->{'Builder'} ne $conf->get('DB_USER')) {
449
send_mail( $pkg->{'Builder'},
450
"package takeover in newer version",
451
"You are building package '$name' in ".
452
"version $version\n".
453
"(as far as I'm informed).\n".
454
$conf->get('DB_USER') . " now has taken the newer ".
455
"version $version for building.".
456
"You can abort the build if you like.\n" );
460
if ($conf->get('DB_OVERRIDE')) {
461
print "User $pkg->{'Builder'} had already ",
462
"taken the following package,\n",
463
"but overriding this as you request:\n";
464
send_mail( $pkg->{'Builder'}, "package takeover",
465
"The package '$name' (version $version) that ".
466
"was locked by you\n".
467
"has been taken over by " . $conf->get('DB_USER') . "\n" );
469
elsif ($pkg->{'Builder'} eq $conf->get('DB_USER')) {
470
print "$name: Note: already taken by you.\n";
471
print "$name: ok\n" if $conf->get('VERBOSE');
476
$reason = "already taken by $pkg->{'Builder'}";
477
$reason .= " (in newer version $pkg->{'Version'})"
478
if !version_eq($pkg->{'Version'}, $version);
482
elsif ($pkg->{'State'} =~ /^Failed/ &&
483
pkg_version_eq($pkg, $version)) {
484
if ($conf->get('DB_OVERRIDE')) {
485
print "The following package previously failed ",
486
"(by $pkg->{'Builder'})\n",
487
"but overriding this as you request:\n";
488
send_mail( $pkg->{'Builder'}, "failed package takeover",
489
"The package '$name' (version $version) that ".
490
"is locked by you\n".
491
"and has failed previously has been taken over ".
492
"by " . $conf->get('DB_USER') . "\n" )
493
if $pkg->{'Builder'} ne $conf->get('DB_USER');
497
$reason = "build of $version failed previously:\n ";
498
$reason .= join( "\n ", split( "\n", $pkg->{'Failed'} ));
499
$reason .= "\nalso the package doesn't need builing"
500
if $pkg->{'State'} eq 'Failed-Removed';
506
if ($pkg->{'Binary-NMU-Version'}) {
507
print "$name: Warning: needs binary NMU $pkg->{'Binary-NMU-Version'}\n" .
508
"$pkg->{'Binary-NMU-Changelog'}\n";
511
print "$name: Warning: Previous version failed!\n"
512
if $pkg->{'Previous-State'} =~ /^Failed/ ||
513
$pkg->{'State'} =~ /^Failed/;
515
change_state( $pkg, 'Building' );
516
$pkg->{'Package'} = $name;
517
$pkg->{'Version'} = $version;
518
$pkg->{'Builder'} = $conf->get('DB_USER');
519
log_ta( $pkg, "--take" );
520
$db->set_package($pkg);
521
print "$name: $ok\n" if $conf->get('VERBOSE');
524
print "$name: NOT OK!\n $reason\n";
528
sub add_one_attempted ($$) {
531
my $pkg = $db->get_package($name);
533
if (!defined($pkg)) {
534
print "$name: not registered yet.\n";
538
if ($pkg->{'State'} ne "Building" ) {
539
print "$name: not taken for building (state is $pkg->{'State'}). ",
543
if ($pkg->{'Builder'} ne $conf->get('USERNAME')) {
544
print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
547
elsif ( !pkg_version_eq($pkg, $version) ) {
548
print "$name: version mismatch ".
549
"$(pkg->{'Version'} ".
550
"by $pkg->{'Builder'})\n";
554
change_state( $pkg, 'Build-Attempted' );
555
log_ta( $pkg, "--attempted" );
556
$db->set_package($pkg);
557
print "$name: registered as uploaded\n" if $conf->get('VERBOSE');
560
sub add_one_built ($$) {
563
my $pkg = $db->get_package($name);
565
if (!defined($pkg)) {
566
print "$name: not registered yet.\n";
570
if ($pkg->{'State'} ne "Building" ) {
571
print "$name: not taken for building (state is $pkg->{'State'}). ",
575
if ($pkg->{'Builder'} ne $conf->get('USERNAME')) {
576
print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
579
elsif ( !pkg_version_eq($pkg, $version) ) {
580
print "$name: version mismatch ".
581
"$(pkg->{'Version'} ".
582
"by $pkg->{'Builder'})\n";
585
change_state( $pkg, 'Built' );
586
log_ta( $pkg, "--built" );
587
$db->set_package($pkg);
588
print "$name: registered as built\n" if $conf->get('VERBOSE');
591
sub add_one_uploaded ($$) {
594
my $pkg = $db->get_package($name);
596
if (!defined($pkg)) {
597
print "$name: not registered yet.\n";
601
if ($pkg->{'State'} eq "Uploaded" &&
602
pkg_version_eq($pkg,$version)) {
603
print "$name: already uploaded\n";
606
if (!isin( $pkg->{'State'}, qw(Building Built Build-Attempted))) {
607
print "$name: not taken for building (state is $pkg->{'State'}). ",
611
if ($pkg->{'Builder'} ne $conf->get('DB_USER')) {
612
print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
615
# strip epoch -- buildd-uploader used to go based on the filename.
616
# (to remove at some point)
618
($pkgver = $pkg->{'Version'}) =~ s/^\d+://;
619
$version =~ s/^\d+://; # for command line use
620
if ($pkg->{'Binary-NMU-Version'} ) {
621
my $nmuver = binNMU_version($pkgver, $pkg->{'Binary-NMU-Version'});
622
if (!version_eq( $nmuver, $version )) {
623
print "$name: version mismatch ($nmuver registered). ",
627
} elsif (!version_eq($pkgver, $version)) {
628
print "$name: version mismatch ($pkg->{'Version'} registered). ",
633
change_state( $pkg, 'Uploaded' );
634
log_ta( $pkg, "--uploaded" );
635
$db->set_package($pkg);
636
print "$name: registered as uploaded\n" if $conf->get('VERBOSE');
639
sub add_one_failed ($$) {
643
my $pkg = $db->get_package($name);
645
if (!defined($pkg)) {
646
print "$name: not registered yet.\n";
649
$state = $pkg->{'State'};
651
if ($state eq "Not-For-Us") {
652
print "$name: not suitable for this architecture anyway. Skipping.\n";
655
elsif ($state eq "Failed-Removed") {
656
print "$name: failed previously and doesn't need building. Skipping.\n";
659
elsif ($state eq "Installed") {
660
print "$name: Is already installed in archive. Skipping.\n";
663
elsif ($pkg->{'Builder'} &&
664
(($conf->get('DB_USER') ne $pkg->{'Builder'}) &&
665
!($pkg->{'Builder'} =~ /^(\w+)-\w+/ && $1 eq $conf->get('DB_USER')))) {
666
print "$name: not taken by you, but by ".
667
"$pkg->{'Builder'}. Skipping.\n";
670
elsif ( !pkg_version_eq($pkg, $version) ) {
671
print "$name: version mismatch ".
672
"$(pkg->{'Version'} ".
673
"by $pkg->{'Builder'})\n";
677
$cat = $conf->get('DB_CATEGORY');
678
if (!$cat && $conf->get('DB_FAIL_REASON') =~ /^\[([^\]]+)\]/) {
680
$cat = category($cat);
681
$cat = "" if !defined($cat);
682
my $fail_reason = $conf->get('DB_FAIL_REASON');
683
$fail_reason =~ s/^\[[^\]]+\][ \t]*\n*//;
684
$conf->set('DB_FAIL_REASON', $fail_reason);
687
if ($state eq "Needs-Build") {
688
print "$name: Warning: not registered for building previously, ".
689
"but processing anyway.\n";
691
elsif ($state eq "Uploaded") {
692
print "$name: Warning: marked as uploaded previously, ".
693
"but processing anyway.\n";
695
elsif ($state eq "Dep-Wait") {
696
print "$name: Warning: marked as waiting for dependencies, ".
697
"but processing anyway.\n";
699
elsif ($state eq "Failed") {
700
print "$name: already registered as failed; will append new message\n"
701
if $conf->get('DB_FAIL_REASON');
702
print "$name: already registered as failed; changing category\n"
706
if (($cat eq "reminder-sent" || $cat eq "nmu-offered") &&
707
exists $pkg->{'Failed-Category'} &&
708
$pkg->{'Failed-Category'} ne $cat) {
709
(my $action = $cat) =~ s/-/ /;
710
$conf->set('DB_FAIL_REASON',
711
$conf->get('DB_FAIL_REASON') . "\n$short_date: $action");
714
change_state( $pkg, 'Failed' );
715
$pkg->{'Builder'} = $conf->get('DB_USER');
716
$pkg->{'Failed'} .= "\n" if $pkg->{'Failed'};
717
$pkg->{'Failed'} .= $conf->get('DB_FAIL_REASON');
718
$pkg->{'Failed-Category'} = $cat if $cat;
719
if (defined $pkg->{'PermBuildPri'}) {
720
$pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
722
delete $pkg->{'BuildPri'};
724
log_ta( $pkg, "--failed" );
725
$db->set_package($pkg);
726
print "$name: registered as failed\n" if $conf->get('VERBOSE');
729
sub add_one_notforus ($$) {
732
my $pkg = $db->get_package($name);
734
if ($pkg->{'State'} eq 'Not-For-Us') {
735
# reset Not-For-Us state in case it's called twice; this is
736
# the only way to get a package out of this state...
737
# There is no really good state in which such packages should
738
# be put :-( So use Failed for now.
739
change_state( $pkg, 'Failed' );
740
$pkg->{'Package'} = $name;
741
$pkg->{'Failed'} = "Was Not-For-Us previously";
742
delete $pkg->{'Builder'};
743
delete $pkg->{'Depends'};
744
log_ta( $pkg, "--no-build(rev)" );
745
print "$name: now not unsuitable anymore\n";
747
send_mail( $conf->get('DB_NOTFORUS_MAINTAINER_EMAIL'),
748
"$name moved out of Not-For-Us state",
749
"The package '$name' has been moved out of the Not-For-Us ".
750
"state by " . $conf->get('DB_USER') . ".\n".
751
"It should probably also be removed from ".
752
"Packages-arch-specific or\n".
753
"the action was wrong.\n" )
754
if $conf->get('DB_NOTFORUS_MAINTAINER_EMAIL');
757
change_state( $pkg, 'Not-For-Us' );
758
$pkg->{'Package'} = $name;
759
delete $pkg->{'Builder'};
760
delete $pkg->{'Depends'};
761
delete $pkg->{'BuildPri'};
762
delete $pkg->{'Binary-NMU-Version'};
763
delete $pkg->{'Binary-NMU-Changelog'};
764
log_ta( $pkg, "--no-build" );
765
print "$name: registered as unsuitable\n" if $conf->get('VERBOSE');
767
send_mail( $conf->get('DB_NOTFORUS_MAINTAINER_EMAIL'),
768
"$name set to Not-For-Us",
769
"The package '$name' has been set to state Not-For-Us ".
770
"by " . $conf->get('DB_USER') . ".\n".
771
"It should probably also be added to ".
772
"Packages-arch-specific or\n".
773
"the Not-For-Us state is wrong.\n" )
774
if $conf->get('DB_NOTFORUS_MAINTAINER_EMAIL');
776
$db->set_package($pkg);
779
sub add_one_needsbuild ($$) {
783
my $pkg = $db->get_package($name);
785
if (!defined($pkg)) {
786
print "$name: not registered; can't give back.\n";
789
$state = $pkg->{'State'};
791
if ($state eq "Dep-Wait") {
792
if ($conf->get('DB_OVERRIDE')) {
793
print "$name: Forcing source dependency list to be cleared\n";
796
print "$name: waiting for source dependencies. Skipping\n",
797
" (use --override to clear dependency list and ",
798
"give back anyway)\n";
802
elsif (!isin( $state, qw(Building Built Build-Attempted))) {
803
print "$name: not taken for building (state is $state).";
804
if ($conf->get('DB_OVERRIDE')) {
805
print "\n$name: Forcing give-back\n";
808
print " Skipping.\n";
812
if (defined ($pkg->{'Builder'}) && $conf->get('DB_USER') ne $pkg->{'Builder'} &&
813
!($pkg->{'Builder'} =~ /^(\w+)-\w+/ && $1 eq $conf->get('DB_USER'))) {
814
print "$name: not taken by you, but by ".
815
"$pkg->{'Builder'}. Skipping.\n";
818
if (!pkg_version_eq($pkg, $version)) {
819
print "$name: version mismatch ($pkg->{'Version'} registered). ",
823
change_state( $pkg, 'Needs-Build' );
824
delete $pkg->{'Builder'};
825
delete $pkg->{'Depends'};
826
log_ta( $pkg, "--give-back" );
827
$db->set_package($pkg);
828
print "$name: given back\n" if $conf->get('VERBOSE');
831
sub set_one_binnmu ($$) {
834
my $pkg = $db->get_package($name);
837
if (!defined($pkg)) {
838
print "$name: not registered; can't register for binNMU.\n";
841
my $db_ver = $pkg->{'Version'};
843
if (!version_eq($db_ver, $version)) {
844
print "$name: version mismatch ($db_ver registered). ",
848
$state = $pkg->{'State'};
850
if (defined $pkg->{'Binary-NMU-Version'}) {
851
if ($conf->get('DB_BIN_NMU_VERSION') == 0) {
852
change_state( $pkg, 'Installed' );
853
delete $pkg->{'Builder'};
854
delete $pkg->{'Depends'};
855
delete $pkg->{'Binary-NMU-Version'};
856
delete $pkg->{'Binary-NMU-Changelog'};
857
} elsif ($conf->get('DB_BIN_NMU_VERSION') <= $pkg->{'Binary-NMU-Version'}) {
858
print "$name: already building binNMU $pkg->{'Binary-NMU-Version'}\n";
861
$pkg->{'Binary-NMU-Version'} = $conf->get('DB_BIN_NMU_VERSION');
862
$pkg->{'Binary-NMU-Changelog'} = $conf->get('DB_FAIL_REASON');
863
$pkg->{'Notes'} = 'out-of-date';
864
$pkg->{'BuildPri'} = $pkg->{'PermBuildPri'}
865
if (defined $pkg->{'PermBuildPri'});
867
log_ta( $pkg, "--binNMU" );
868
$db->set_package($pkg);
870
} elsif ($conf->get('DB_BIN_NMU_VERSION')) {
871
print "${name}_$version: no scheduled binNMU to cancel.\n";
875
if ($state ne 'Installed') {
876
print "${name}_$version: not installed; can't register for binNMU.\n";
880
my $fullver = binNMU_version($version,$conf->get('DB_BIN_NMU_VERSION'));
881
if (version_lesseq($fullver, $pkg->{'Installed-Version'})) {
882
print "$name: binNMU $fullver is not newer than current version $pkg->{'Installed-Version'}\n";
886
change_state( $pkg, 'Needs-Build' );
887
delete $pkg->{'Builder'};
888
delete $pkg->{'Depends'};
889
$pkg->{'Binary-NMU-Version'} = $conf->get('DB_BIN_NMU_VERSION');
890
$pkg->{'Binary-NMU-Changelog'} = $conf->get('DB_FAIL_REASON');
891
$pkg->{'Notes'} = 'out-of-date';
892
log_ta( $pkg, "--binNMU" );
893
$db->set_package($pkg);
894
print "${name}: registered for binNMU $fullver\n" if $conf->get('VERBOSE');
897
sub set_one_buildpri ($$$) {
901
my $pkg = $db->get_package($name);
904
if (!defined($pkg)) {
905
print "$name: not registered; can't set priority.\n";
908
$state = $pkg->{'State'};
910
if ($state eq "Not-For-Us") {
911
print "$name: not suitable for this architecture. Skipping.\n";
913
} elsif ($state eq "Failed-Removed") {
914
print "$name: failed previously and doesn't need building. Skipping.\n";
917
if (!pkg_version_eq($pkg, $version)) {
918
print "$name: version mismatch ($pkg->{'Version'} registered). ",
922
if ( $conf->get('DB_BUILD_PRIORITY') == 0 ) {
923
delete $pkg->{'BuildPri'}
924
if $key eq 'PermBuildPri' and defined $pkg->{'BuildPri'}
925
and $pkg->{'BuildPri'} == $pkg->{$key};
928
$pkg->{'BuildPri'} = $conf->get('DB_BUILD_PRIORITY')
929
if $key eq 'PermBuildPri';
930
$pkg->{$key} = $conf->get('DB_BUILD_PRIORITY');
932
$db->set_package($pkg);
933
print "$name: set to build priority " .
934
$conf->get('DB_BUILD_PRIORITY') . "\n" if $conf->get('VERBOSE');
937
sub add_one_depwait ($$) {
941
my $pkg = $db->get_package($name);
943
if (!defined($pkg)) {
944
print "$name: not registered yet.\n";
947
$state = $pkg->{'State'};
949
if ($state eq "Dep-Wait") {
950
print "$name: merging with previously registered dependencies\n";
953
if (isin( $state, qw(Needs-Build Failed))) {
954
print "$name: Warning: not registered for building previously, ".
955
"but processing anyway.\n";
957
elsif ($state eq "Not-For-Us") {
958
print "$name: not suitable for this architecture anyway. Skipping.\n";
961
elsif ($state eq "Failed-Removed") {
962
print "$name: failed previously and doesn't need building. Skipping.\n";
965
elsif ($state eq "Installed") {
966
print "$name: Is already installed in archive. Skipping.\n";
969
elsif ($state eq "Uploaded") {
970
print "$name: Is already uploaded. Skipping.\n";
973
elsif ($pkg->{'Builder'} &&
974
$conf->get('DB_USER') ne $pkg->{'Builder'}) {
975
print "$name: not taken by you, but by ".
976
"$pkg->{'Builder'}. Skipping.\n";
979
elsif ( !pkg_version_eq($pkg,$version)) {
980
print "$name: version mismatch ".
981
"($pkg->{'Version'} ".
982
"by $pkg->{'Builder'})\n";
985
elsif ($conf->get('DB_FAIL_REASON') =~ /^\s*$/ ||
986
!parse_deplist( $conf->get('DB_FAIL_REASON'), 1 )) {
987
print "$name: Bad dependency list\n";
990
change_state( $pkg, 'Dep-Wait' );
991
$pkg->{'Builder'} = $conf->get('DB_USER');
992
if (defined $pkg->{'PermBuildPri'}) {
993
$pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
995
delete $pkg->{'BuildPri'};
997
my $deplist = parse_deplist( $pkg->{'Depends'}, 0 );
998
my $new_deplist = parse_deplist( $conf->get('DB_FAIL_REASON'), 0 );
999
# add new dependencies, maybe overwriting old entries
1000
foreach (keys %$new_deplist) {
1001
$deplist->{$_} = $new_deplist->{$_};
1003
$pkg->{'Depends'} = build_deplist($deplist);
1004
log_ta( $pkg, "--dep-wait" );
1005
$db->set_package($pkg);
1006
print "$name: registered as waiting for dependencies\n" if $conf->get('VERBOSE');
1010
sub parse_sources ($) {
1016
local($/) = ""; # read in paragraph mode
1018
my( $version, $arch, $section, $priority, $builddep, $buildconf, $binaries );
1020
/^Package:\s*(\S+)$/mi and $name = $1;
1021
/^Version:\s*(\S+)$/mi and $version = $1;
1022
/^Architecture:\s*(\S+)$/mi and $arch = $1;
1023
/^Section:\s*(\S+)$/mi and $section = $1;
1024
/^Priority:\s*(\S+)$/mi and $priority = $1;
1025
/^Build-Depends:\s*(.*)$/mi and $builddep = $1;
1026
/^Build-Conflicts:\s*(.*)$/mi and $buildconf = $1;
1027
/^Binary:\s*(.*)$/mi and $binaries = $1;
1029
next if (defined $srcver{$name} and version_less( $version, $srcver{$name} ));
1030
$srcver{$name} = $version;
1032
$buildconf = join( ", ", map { "!$_" } split( /\s*,\s*/, $buildconf ));
1034
$builddep .= "," . $buildconf;
1036
$builddep = $buildconf;
1040
$pkgs{$name}{'dep'} = defined $builddep ? $builddep : "";
1041
$pkgs{$name}{'ver'} = $version;
1042
$pkgs{$name}{'bin'} = $binaries;
1043
my $pkg = $db->get_package($name);
1048
if ($arch eq "all" && !version_less( $version, $pkg->{'Version'} )) {
1049
# package is now Arch: all, delete it from db
1050
change_state( $pkg, 'deleted' );
1051
log_ta( $pkg, "--merge-sources" );
1052
print "$name ($pkg->{'Version'}): deleted ".
1053
"from database, because now Arch: all\n"
1054
if $conf->get('VERBOSE');
1055
$db->del_package($pkg);
1059
# The "Version" should always be the source version --
1060
# not a possible binNMU version number.
1061
$pkg->{'Version'} = $version, $change++
1062
if ($pkg->{'State'} eq 'Installed' and
1063
!version_eq( $pkg->{'Version'}, $version));
1064
# Always update priority and section, if available
1065
$pkg->{'Priority'} = $priority, $change++
1066
if defined $priority && (!defined($pkg->{'Priority'}) ||
1067
$pkg->{'Priority'} ne $priority);
1068
$pkg->{'Section'} = $section, $change++
1069
if defined $section && (!defined($pkg->{'Section'}) ||
1070
$pkg->{'Section'} ne $section);
1071
$db->set_package($pkg) if $change;
1074
# Now that we only have the latest source version, build the list
1075
# of binary packages from the Sources point of view
1076
foreach $name (keys %pkgs) {
1077
foreach my $bin (split( /\s*,\s*/, $pkgs{$name}{'bin'} ) ) {
1078
$merge_binsrc{$bin} = $name;
1081
# remove installed packages that no longer have source available
1082
# or binaries installed
1083
foreach $name ($db->list_packages()) {
1084
my $pkg = $db->get_package($name);
1085
if (not defined($pkgs{$name})) {
1086
change_state( $pkg, 'deleted' );
1087
log_ta( $pkg, "--merge-sources" );
1088
print "$name ($pkg->{'Version'}): ".
1089
"deleted from database, because ".
1090
"not in Sources anymore\n"
1091
if $conf->get('VERBOSE');
1092
$db->del_package($name);
1094
next if !isin( $pkg->{'State'}, qw(Installed) );
1095
if ($full && not defined $merge_srcvers{$name}) {
1096
change_state( $pkg, 'deleted' );
1097
log_ta( $pkg, "--merge-sources" );
1098
print "$name ($pkg->{'Version'}): ".
1099
"deleted from database, because ".
1100
"binaries don't exist anymore\n"
1101
if $conf->get('VERBOSE');
1102
$db->del_package($name);
1103
} elsif ($full && version_less( $merge_srcvers{$name}, $pkg->{'Version'})) {
1104
print "$name ($pkg->{'Version'}): ".
1105
"package is Installed but binaries are from ".
1106
$merge_srcvers{$name}. "\n"
1107
if $conf->get('VERBOSE');
1114
# This function looks through a Packages file and sets the state of
1115
# packages to 'Installed'
1116
sub parse_packages () {
1119
local($/) = ""; # read in paragraph mode
1121
my( $name, $version, $depends, $source, $sourcev, $architecture, $provides, $binaryv, $binnmu );
1123
/^Package:\s*(\S+)$/mi and $name = $1;
1124
/^Version:\s*(\S+)$/mi and $version = $1;
1125
/^Depends:\s*(.*)$/mi and $depends = $1;
1126
/^Source:\s*(\S+)(\s*\((\S+)\))?$/mi and ($source,$sourcev) = ($1, $3);
1127
/^Architecture:\s*(\S+)$/mi and $architecture = $1;
1128
/^Provides:\s*(.*)$/mi and $provides = $1;
1130
next if !$name || !$version;
1131
next if ($conf->get('ARCH') ne $architecture and $architecture ne "all");
1132
next if (defined ($installed->{$name}) and $installed->{$name}{'Version'} ne "" and
1133
version_lesseq( $version, $installed->{$name}{'Version'} ));
1134
$installed->{$name}{'Version'} = $version;
1135
$installed->{$name}{'Depends'} = $depends;
1136
$installed->{$name}{'all'} = 1 if $architecture eq "all";
1137
undef $installed->{$name}{'Provider'};
1138
$installed->{$name}{'Source'} = $source ? $source : $name;
1141
foreach (split( /\s*,\s*/, $provides )) {
1142
if (not defined ($installed->{$_})) {
1143
$installed->{$_}{'Version'} = "";
1144
$installed->{$_}{'Provider'} = $name;
1148
if ( $version =~ /\+b(\d+)$/ ) {
1151
$version = $sourcev if $sourcev;
1152
$binaryv = $version;
1153
$binaryv =~ s/\+b\d+$//;
1154
$installed->{$name}{'Sourcev'} = $sourcev ? $sourcev : $binaryv;
1155
$binaryv .= "+b$binnmu" if defined($binnmu);
1157
next if $architecture ne $conf->get('ARCH');
1158
$name = $source if $source;
1159
next if defined($merge_srcvers{$name}) and $merge_srcvers{$name} eq $version;
1161
$merge_srcvers{$name} = $version;
1163
my $pkg = $db->get_package($name);
1166
if (isin( $pkg->{'State'}, qw(Not-For-Us)) ||
1167
(isin($pkg->{'State'}, qw(Installed)) &&
1168
version_lesseq($binaryv, $pkg->{'Installed-Version'}))) {
1169
print "Skipping $name because State == $pkg->{'State'}\n"
1170
if $conf->get('VERBOSE') >= 2;
1173
if ($pkg->{'Binary-NMU-Version'} ) {
1174
my $nmuver = binNMU_version($pkg->{'Version'}, $pkg->{'Binary-NMU-Version'});
1175
if (version_less( $binaryv, $nmuver )) {
1176
print "Skipping $name ($version) because have newer ".
1177
"version ($nmuver) in db.\n"
1178
if $conf->get('VERBOSE') >= 2;
1181
} elsif (version_less($version, $pkg->{'Version'})) {
1182
print "Skipping $name ($version) because have newer ".
1183
"version ($pkg->{'Version'}) in db.\n"
1184
if $conf->get('VERBOSE') >= 2;
1188
if (!pkg_version_eq($pkg, $version) &&
1189
$pkg->{'State'} ne "Installed") {
1190
warn "Warning: $name: newer version than expected appeared ".
1191
"in archive ($version vs. $pkg->{'Version'})\n";
1192
delete $pkg->{'Builder'};
1195
if (!isin( $pkg->{'State'}, qw(Uploaded) )) {
1196
warn "Warning: Package $name was not in uploaded state ".
1197
"before (but in '$pkg->{'State'}').\n";
1198
delete $pkg->{'Builder'};
1199
delete $pkg->{'Depends'};
1203
$pkg->{'Version'} = $version;
1206
change_state( $pkg, 'Installed' );
1207
$pkg->{'Package'} = $name;
1208
$pkg->{'Installed-Version'} = $binaryv;
1209
if (defined $pkg->{'PermBuildPri'}) {
1210
$pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
1212
delete $pkg->{'BuildPri'};
1214
$pkg->{'Version'} = $version
1215
if version_less( $pkg->{'Version'}, $version);
1216
delete $pkg->{'Binary-NMU-Version'};
1217
delete $pkg->{'Binary-NMU-Changelog'};
1218
log_ta( $pkg, "--merge-packages" );
1219
$db->set_package($name) = $pkg;
1220
print "$name ($version) is up-to-date now.\n" if $conf->get('VERBOSE');
1223
check_dep_wait( "--merge-packages", $installed );
1227
sub pretend_avail (@) {
1228
my ($package, $name, $version, $installed);
1230
foreach $package (@_) {
1231
$package =~ s,^.*/,,; # strip path
1232
$package =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
1233
$package =~ s/_[\w\d]+\.changes$//; # strip extension
1234
if ($package =~ /^([\w\d.+-]+)_([\w\d:.+~-]+)/) {
1235
($name,$version) = ($1,$2);
1238
warn "$package: can't extract package name and version ".
1242
$installed->{$name}{'Version'} = $version;
1245
check_dep_wait( "--pretend-avail", $installed );
1248
sub check_dep_wait ($$) {
1250
my $installed = shift;
1252
# check all packages in state Dep-Wait if dependencies are all
1255
foreach $name ($db->list_packages()) {
1256
my $pkg = $db->get_package($name);
1257
next if $pkg->{'State'} ne "Dep-Wait";
1258
my $deps = $pkg->{'Depends'};
1260
print "$name: was in state Dep-Wait, but with empty ",
1262
goto make_needs_build;
1264
my $deplist = parse_deplist($deps, 0);
1268
foreach (keys %$deplist) {
1269
if (!exists $installed->{$_} ||
1270
($deplist->{$_}->{'Rel'} && $deplist->{$_}->{'Version'} &&
1271
!version_compare( $installed->{$_}{'Version'},
1272
$deplist->{$_}->{'Rel'},
1273
$deplist->{$_}->{'Version'}))) {
1275
$new_deplist->{$_} = $deplist->{$_};
1278
push( @removed_deps, $_ );
1283
change_state( $pkg, 'Needs-Build' );
1284
log_ta( $pkg, $action );
1285
delete $pkg->{'Builder'};
1286
delete $pkg->{'Depends'};
1287
print "$name ($pkg->{'Version'}) has all ",
1288
"dependencies available now\n" if $conf->get('VERBOSE');
1290
$db->set_package($pkg);
1292
elsif (@removed_deps) {
1293
$pkg->{'Depends'} = build_deplist( $new_deplist );
1294
print "$name ($pkg->{'Version'}): some dependencies ",
1295
"(@removed_deps) available now, but not all yet\n"
1296
if $conf->get('VERBOSE');
1297
$db->set_package($pkg);
1302
# This function accepts quinn-diff output (either from a file named on
1303
# the command line, or on stdin) and sets the packages named there to
1304
# state 'Needs-Build'.
1305
sub parse_quinn_diff ($) {
1306
my $partial = shift;
1312
next if !m,^([-\w\d/]*)/ # section
1313
([-\w\d.+]+)_ # package name
1314
([\w\d:.~+-]+)\.dsc\s* # version
1315
\[([^:]*): # priority
1316
([^]]+)\]\s*$,x; # rest of notes
1317
my($section,$name,$version,$priority,$notes) = ($1, $2, $3, $4, $5);
1318
$quinn_pkgs{$name}++;
1319
$section ||= "unknown";
1320
$priority ||= "unknown";
1321
$priority = "unknown" if $priority eq "-";
1322
$priority = "standard" if ($name eq "debian-installer");
1324
my $pkg = $db->get_package($name);
1326
# Always update section and priority.
1327
if (defined($pkg)) {
1329
$pkg->{'Section'} = $section, $change++ if not defined
1330
$pkg->{'Section'} or $section ne "unknown";
1331
$pkg->{'Priority'} = $priority, $change++ if not defined
1332
$pkg->{'Priority'} or $priority ne "unknown";
1335
if (defined($pkg) &&
1336
$pkg->{'State'} =~ /^Dep-Wait/ &&
1337
version_less( $pkg->{'Version'}, $version )) {
1338
change_state( $pkg, 'Dep-Wait' );
1339
$pkg->{'Version'} = $version;
1340
delete $pkg->{'Binary-NMU-Version'};
1341
delete $pkg->{'Binary-NMU-Changelog'};
1342
log_ta( $pkg, "--merge-quinn" );
1344
print "$name ($version) still waiting for dependencies.\n"
1345
if $conf->get('VERBOSE');
1347
elsif (defined($pkg) &&
1348
$pkg->{'State'} =~ /-Removed$/ &&
1349
version_eq($pkg->{'Version'}, $version)) {
1350
# reinstantiate a package that has been removed earlier
1351
# (probably due to a quinn-diff malfunction...)
1352
my $newstate = $pkg->{'State'};
1353
$newstate =~ s/-Removed$//;
1354
change_state( $pkg, $newstate );
1355
$pkg->{'Version'} = $version;
1356
$pkg->{'Notes'} = $notes;
1357
log_ta( $pkg, "--merge-quinn" );
1359
print "$name ($version) reinstantiated to $newstate.\n"
1360
if $conf->get('VERBOSE');
1362
elsif (defined($pkg) &&
1363
$pkg->{'State'} eq "Not-For-Us" &&
1364
version_less( $pkg->{'Version'}, $version )) {
1365
# for Not-For-Us packages just update the version etc., but
1367
change_state( $pkg, "Not-For-Us" );
1368
$pkg->{'Package'} = $name;
1369
$pkg->{'Version'} = $version;
1370
$pkg->{'Notes'} = $notes;
1371
delete $pkg->{'Builder'};
1372
log_ta( $pkg, "--merge-quinn" );
1374
print "$name ($version) still Not-For-Us.\n" if $conf->get('VERBOSE');
1376
elsif (!defined($pkg) ||
1377
$pkg->{'State'} ne "Not-For-Us" &&
1378
(version_less( $pkg->{'Version'}, $version ) ||
1379
($pkg->{'State'} eq "Installed" && version_less($pkg->{'Installed-Version'}, $version)))) {
1380
if (defined( $pkg->{'State'} ) &&
1381
isin($pkg->{'State'}, qw(Building Built Build-Attempted))) {
1382
send_mail( $pkg->{'Builder'},
1383
"new version of $name (dist=" . $conf->get('DISTRIBUTION') . ")",
1384
"As far as I'm informed, you're currently ".
1385
"building the package $name\n".
1386
"in version $pkg->{'Version'}.\n\n".
1387
"Now there's a new source version $version. ".
1388
"If you haven't finished\n".
1389
"compiling $name yet, you can stop it to ".
1390
"save some work.\n".
1391
"Just to inform you...\n".
1392
"(This is an automated message)\n" );
1393
print "$name: new version ($version) while building ".
1394
"$pkg->{'Version'} -- sending mail ".
1395
"to builder ($pkg->{'Builder'})\n"
1396
if $conf->get('VERBOSE');
1398
change_state( $pkg, 'Needs-Build' );
1399
$pkg->{'Package'} = $name;
1400
$pkg->{'Version'} = $version;
1401
$pkg->{'Section'} = $section;
1402
$pkg->{'Priority'} = $priority;
1403
$pkg->{'Notes'} = $notes;
1404
delete $pkg->{'Builder'};
1405
delete $pkg->{'Binary-NMU-Version'};
1406
delete $pkg->{'Binary-NMU-Changelog'};
1407
log_ta( $pkg, "--merge-quinn" );
1410
print "$name ($version) needs rebuilding now.\n" if $conf->get('VERBOSE');
1412
elsif (defined($pkg) &&
1413
!version_eq( $pkg->{'Version'}, $version ) &&
1414
isin( $pkg->{'State'}, qw(Installed Not-For-Us) )) {
1415
print "$name: skipping because version in db ".
1416
"($pkg->{'Version'}) is >> than ".
1417
"what quinn-diff says ($version) ".
1418
"(state is $pkg->{'State'})\n"
1419
if $conf->get('VERBOSE');
1420
$dubious .= "$pkg->{'State'}: ".
1421
"db ${name}_$pkg->{'Version'} >> ".
1422
"quinn $version\n" if !$partial;
1424
elsif ($conf->get('VERBOSE') >= 2) {
1425
if ($pkg->{'State'} eq "Not-For-Us") {
1426
print "Skipping $name because State == ".
1427
"$pkg->{'State'}\n";
1429
elsif (!version_less($pkg->{'Version'}, $version)) {
1430
print "Skipping $name because version in db ".
1431
"($pkg->{'Version'}) is >= than ".
1432
"what quinn-diff says ($version)\n";
1435
$db->set_package($pkg) if $change;
1439
send_mail( $conf->get('DB_MAINTAINER_EMAIL'),
1440
"Dubious versions in " . $conf->get('DISTRIBUTION') . " " .
1441
$conf->get('DB_BASE_NAME') . " database",
1442
"The following packages have a newer version in the ".
1443
"wanna-build database\n".
1444
"than what quinn-diff says, and this is strange for ".
1446
"It could be caused by a lame mirror, or the version ".
1447
"in the database\n".
1452
# Now re-check the DB for packages in states Needs-Build, Failed,
1453
# or Dep-Wait and remove them if they're not listed anymore by quinn-diff.
1456
foreach $name ($db->list_packages()) {
1457
my $pkg = $db->get_package($name);
1458
next if defined $pkg->{'Binary-NMU-Version'};
1459
next if !isin($pkg->{'State'},
1460
qw(Needs-Build Building Built
1461
Build-Attempted Uploaded Failed
1463
my $virtual_delete = $pkg->{'State'} eq 'Failed';
1465
if (!$quinn_pkgs{$name}) {
1466
change_state( $pkg, $virtual_delete ?
1467
$pkg->{'State'}."-Removed" :
1469
log_ta( $pkg, "--merge-quinn" );
1470
print "$name ($pkg->{'Version'}): ".
1471
($virtual_delete ? "(virtually) " : "") . "deleted ".
1472
"from database, because not in quinn-diff anymore\n"
1473
if $conf->get('VERBOSE');
1474
if ($virtual_delete) {
1475
$db->set_package($pkg);
1477
$db->set_package($name);
1484
sub send_reupload_mail ($$$$$) {
1487
my $version = shift;
1489
my $other_dist = shift;
1492
"Please reupload ${pkg}_${'Version'} for $dist",
1493
"You have recently built (or are currently building)\n".
1494
"${pkg}_${'Version'} for $other_dist.\n".
1495
"This version is now also needed in the $dist distribution.\n".
1496
"Please reupload the files now present in the Debian archive\n".
1497
"(best with buildd-reupload).\n" );
1501
# for sorting priorities and sections
1503
%prioval = ( required => -5,
1511
'debian-installer' => -199,
1529
interpreters => -181,
1541
electronics => -169,
1545
foreach my $i (keys %sectval) {
1546
$sectval{"contrib/$i"} = $sectval{$i}+40;
1547
$sectval{"non-free/$i"} = $sectval{$i}+80;
1549
$sectval{'unknown'} = -165;
1551
%catval = ( "none" => -20,
1552
"uploaded-fixed-pkg" => -19,
1553
"fix-expected" => -18,
1554
"reminder-sent" => -17,
1555
"nmu-offered" => -16,
1559
"compiler-error" => -12 );
1562
sub sort_list_func () {
1565
foreach $letter (split( "", $conf->get('DB_LIST_ORDER') )) {
1566
SWITCH: foreach ($letter) {
1568
my $ap = $a->{'BuildPri'};
1569
my $bp = $b->{'BuildPri'};
1570
$ap = 0 if !defined($ap);
1571
$bp = 0 if !defined($bp);
1573
return $x if $x != 0;
1577
$x = $prioval{$a->{'Priority'}} <=> $prioval{$b->{'Priority'}};
1578
return $x if $x != 0;
1582
$sectval{$a->{'Section'}} = -125 if(!$sectval{$a->{'Section'}});
1583
$sectval{$b->{'Section'}} = -125 if(!$sectval{$b->{'Section'}});
1584
$x = $sectval{$a->{'Section'}} <=> $sectval{$b->{'Section'}};
1585
return $x if $x != 0;
1589
$x = $a->{'Package'} cmp $b->{'Package'};
1590
return $x if $x != 0;
1594
my $ab = $a->{'Builder'};
1595
my $bb = $b->{'Builder'};
1596
$ab = "" if !defined($ab);
1597
$bb = "" if !defined($bb);
1599
return $x if $x != 0;
1605
if (defined($a->{'Notes'})) {
1606
$ax = ($a->{'Notes'} =~ /^(out-of-date|partial)/) ? 0 :
1607
($a->{'Notes'} =~ /^uncompiled/) ? 2 : 1;
1609
if (defined($b->{'Notes'})) {
1610
$bx = ($b->{'Notes'} =~ /^(out-of-date|partial)/) ? 0 :
1611
($b->{'Notes'} =~ /^uncompiled/) ? 2 : 1;
1614
return $x if $x != 0;
1618
my $ca = exists $a->{'Failed-Category'} ?
1619
$a->{'Failed-Category'} : "none";
1620
my $cb = exists $b->{'Failed-Category'} ?
1621
$b->{'Failed-Category'} : "none";
1622
$x = $catval{$ca} <=> $catval{$cb};
1623
return $x if $x != 0;
1627
my $pa = $prioval{$a->{'Priority'}} >
1628
$prioval{'standard'};
1629
my $pb = $prioval{$b->{'Priority'}} >
1630
$prioval{'standard'};
1632
return $x if $x != 0;
1636
my $x = $ctime-parse_date($a->{'State-Change'}) <=> $ctime-parse_date($b->{'State-Change'});
1637
return $x if $x != 0;
1645
sub list_packages ($) {
1647
my( $name, $pkg, @list );
1650
my $user = $conf->get('DB_USER');
1652
foreach $name ($db->list_packages()) {
1653
$pkg = $db->get_package($name);
1654
next if $state ne "all" && $pkg->{'State'} !~ /^\Q$state\E$/i;
1655
next if $user && (lc($state) ne 'needs-build' &&
1656
defined($pkg->{'Builder'}) &&
1657
$pkg->{'Builder'} ne $conf->get('DB_USER'));
1658
next if $conf->get('DB_CATEGORY') && $pkg->{'State'} eq "Failed" &&
1659
$pkg->{'Failed-Category'} ne $conf->get('DB_CATEGORY');
1660
next if ($conf->get('DB_LIST_MIN_AGE') > 0 &&
1661
($ctime-parse_date($pkg->{'State-Change'})) < $conf->get('DB_LIST_MIN_AGE'))||
1662
($conf->get('DB_LIST_MIN_AGE') < 0 &&
1663
($ctime-parse_date($pkg->{'State-Change'})) > -$conf->get('DB_LIST_MIN_AGE'));
1664
push( @list, $pkg );
1667
foreach $pkg (sort sort_list_func @list) {
1668
print "$pkg->{'Section'}/$pkg->{'Package'}_$pkg->{'Version'}";
1669
print ": $pkg->{'State'}"
1671
print " by $pkg->{'Builder'}"
1672
if $pkg->{'State'} ne "Needs-Build" && $pkg->{'Builder'};
1673
print " [$pkg->{'Priority'}:";
1674
print "$pkg->{'Notes'}"
1675
if defined($pkg->{'Notes'});
1676
print ":PREV-FAILED"
1677
if defined($pkg->{'Previous-State'}) &&
1678
$pkg->{'Previous-State'} =~ /^Failed/;
1679
print ":bp{" . $pkg->{'BuildPri'} . "}"
1680
if exists $pkg->{'BuildPri'};
1681
print ":binNMU{" . $pkg->{'Binary-NMU-Version'} . "}"
1682
if exists $pkg->{'Binary-NMU-Version'};
1684
print " Reasons for failing:\n",
1686
exists $pkg->{'Failed-Category'} ? $pkg->{'Failed-Category'} : "none",
1688
join("\n ",split("\n",$pkg->{'Failed'})), "\n"
1689
if $pkg->{'State'} =~ /^Failed/;
1690
print " Dependencies: $pkg->{'Depends'}\n"
1691
if $pkg->{'State'} eq "Dep-Wait" &&
1692
defined $pkg->{'Depends'};
1693
print " Previous state was $pkg->{'Previous-State'} until ",
1694
"$pkg->{'State-Change'}\n"
1695
if $conf->get('VERBOSE') && $pkg->{'Previous-State'};
1696
print " Previous failing reasons:\n ",
1697
join("\n ",split("\n",$pkg->{'Old-Failed'})), "\n"
1698
if $conf->get('VERBOSE') && $pkg->{'Old-Failed'};
1700
$scnt{$pkg->{'State'}}++ if $state eq "all";
1702
if ($state eq "all") {
1703
foreach (sort keys %scnt) {
1704
print "Total $scnt{$_} package(s) in state $_.\n";
1707
print "Total $cnt package(s)\n";
1711
sub info_packages (@) {
1712
my( $name, $pkg, $key, $dist );
1713
my @firstkeys = qw(Package Version Builder State Section Priority
1714
Installed-Version Previous-State State-Change);
1715
my @dists = $conf->get('DB_INFO_ALL_DISTS') ? keys %{$conf->get('DB_DISTRIBUTIONS')} : ($conf->get('DISTRIBUTION'));
1717
foreach $dist (@dists) {
1718
if ($dist ne $conf->get('DISTRIBUTION')) {
1719
if (!open_db($dist)) {
1720
warn "Cannot open database for $dist!\n";
1721
@dists = grep { $_ ne $dist } @dists;
1726
foreach $name (@_) {
1727
$name =~ s/_.*$//; # strip version
1728
foreach $dist (@dists) {
1729
my $db = $databases{$dist};
1730
my $pname = "$name" . ($conf->get('DB_INFO_ALL_DISTS') ? "($dist)" : "");
1732
$pkg = $db->get_package($name);
1733
if (!defined( $pkg )) {
1734
print "$pname: not registered\n";
1739
foreach $key (@firstkeys) {
1740
next if !exists $pkg->{$key};
1741
my $val = $pkg->{$key};
1743
$val = "\n$val" if isin( $key, qw(Failed Old-Failed));
1745
printf " %-20s: %s\n", $key, $val;
1747
foreach $key (sort keys %$pkg) {
1748
next if isin( $key, @firstkeys );
1749
my $val = $pkg->{$key};
1751
$val = "\n$val" if isin( $key, qw(Failed Old-Failed));
1753
printf " %-20s: %s\n", $key, $val;
1759
sub forget_packages (@) {
1760
my( $name, $pkg, $key, $data );
1762
foreach $name (@_) {
1763
$name =~ s/_.*$//; # strip version
1764
$pkg = $db->get_package($name);
1765
if (!defined( $pkg )) {
1766
print "$name: not registered\n";
1771
foreach $key (sort keys %$pkg) {
1772
my $val = $pkg->{$key};
1775
$data .= sprintf " %-20s: %s\n", $key, $val;
1777
send_mail( $conf->get('DB_MAINTAINER_EMAIL'),
1778
"$name deleted from DB " . $conf->get('DB_BASE_NAME'),
1779
"The package '$name' has been deleted from the database ".
1780
"by " . $conf->get('DB_USER') . ".\n\n".
1781
"Data registered about the deleted package:\n".
1782
"$data\n" ) if $conf->get('DB_MAINTAINER_EMAIL');
1783
change_state( $pkg, 'deleted' );
1784
log_ta( $pkg, "--forget" );
1785
$db->set_package($name);
1786
print "$name: deleted from database\n" if $conf->get('VERBOSE');
1790
sub forget_users (@) {
1793
foreach $name (@_) {
1794
if (!$db->del_user($name)) {
1795
print "$name: not registered\n";
1799
print "$name: deleted from database\n" if $conf->get('VERBOSE');
1803
sub create_maintlock () {
1804
my $lockfile = db_filename("maintenance") . ".lock";
1808
print "Creating maintenance lock\n" if $conf->get('VERBOSE') >= 2;
1810
if (!sysopen( F, $lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644 )){
1812
# lock file exists, wait
1813
goto repeat if !open( F, "<$lockfile" );
1816
if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
1817
warn "Bad maintenance lock file contents -- still trying\n";
1820
my($pid, $usr) = ($1, $2);
1821
if (kill( 0, $pid ) == 0 && $! == ESRCH) {
1822
# process doesn't exist anymore, remove stale lock
1823
print "Removing stale lock file (pid $pid, user $usr)\n";
1824
unlink( $lockfile );
1827
warn "Maintenance lock already exists by $usr -- ".
1828
"please wait\n" if $try == 0;
1831
die "Lock still present after 120 * 60 seconds.\n";
1836
die "Can't create maintenance lock $lockfile: $!\n";
1838
F->print(getppid(), " " . $conf->get('USERNAME') . "\n");
1842
sub remove_maintlock () {
1843
my $lockfile = db_filename("maintenance") . ".lock";
1845
print "Removing maintenance lock\n" if $conf->get('VERBOSE') >= 2;
1849
sub waitfor_maintlock () {
1850
my $lockfile = db_filename("maintenance") . ".lock";
1854
print "Checking for maintenance lock\n" if $conf->get('VERBOSE') >= 2;
1856
if (open( F, "<$lockfile" )) {
1859
if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
1860
warn "Bad maintenance lock file contents -- still trying\n";
1863
my($pid, $usr) = ($1, $2);
1864
if (kill( 0, $pid ) == 0 && $! == ESRCH) {
1865
# process doesn't exist anymore, remove stale lock
1866
print "Removing stale maintenance lock (pid $pid, user $usr)\n";
1867
unlink( $lockfile );
1870
warn "Databases locked for general maintenance by $usr -- ".
1871
"please wait\n" if $try == 0;
1874
die "Lock still present after 120 * 60 seconds.\n";
1881
sub change_state ($$) {
1883
my $newstate = shift;
1885
my $state = $pkg->{'State'};
1887
return if defined($state) and $state eq $newstate;
1888
$pkg->{'Previous-State'} = $state if defined($state);
1890
$pkg->{'State-Change'} = $curr_date;
1892
if (defined($state) and $state eq 'Failed') {
1893
$pkg->{'Old-Failed'} =
1894
"-"x20 . " $pkg->{'Version'} " . "-"x20 . "\n" .
1895
$pkg->{'Failed'} . "\n" .
1896
$pkg->{'Old-Failed'};
1897
delete $pkg->{'Failed'};
1898
delete $pkg->{'Failed-Category'};
1901
$pkg->{'State'} = $newstate;
1907
my $newdb = $databases{$dist};
1909
if (!defined($newdb)) {
1910
if ($conf->get('DB_TYPE') eq 'mldbm') {
1911
$newdb = Sbuild::DB::MLDBM->new($conf);
1912
} elsif ($conf->get('DB_TYPE') eq 'postgres') {
1913
$newdb = Sbuild::DB::Postgres->new($conf);
1915
die "Unsupported database type '" . $conf->get('DB_TYPE') . "'\n";
1918
$newdb->open(db_filename($dist));
1921
$databases{$dist} = $newdb;
1931
my $dist = $conf->get('DISTRIBUTION');
1935
$prevstate = $pkg->{'Previous-State'};
1936
$str = "$action($dist): $pkg->{'Package'}_$pkg->{'Version'} ".
1937
"changed from $prevstate to $pkg->{'State'} ".
1938
"by " . $conf->get('USERNAME'). " as " . $conf->get('DB_USER') . ".";
1940
my $dbbase = $conf->get('DB_BASE_NAME');
1941
$dbbase =~ m#^([^/]+/)#;
1943
my $transactlog = $conf->get('DB_BASE_DIR') . "/$1" .
1944
$conf->get('DB_TRANSACTION_LOG');
1945
if (!open( LOG, ">>$transactlog" )) {
1946
warn "Can't open log file $transactlog: $!\n";
1949
print LOG "$curr_date: $str\n";
1952
if (!($prevstate eq 'Failed' && $pkg->{'State'} eq 'Failed')) {
1953
$str .= " (with --override)"
1954
if $conf->get('DB_OVERRIDE');
1955
$mail_logs .= "$str\n";
1964
my $dist_order = $conf->get('DB_DISTRIBUTIONS');
1966
return $dist_order->{$d1}->{'priority'} <=> $dist_order->{$d2}->{'priority'};
1971
sub send_mail ($$$) {
1973
my $subject = shift;
1976
my $from = $conf->get('DB_MAINTAINER_EMAIL');
1977
my $domain = $conf->get('DB_MAIL_DOMAIN');
1979
if (defined($domain)) {
1980
$from .= "\@$domain" if $from !~ /\@/;
1981
$to .= '@$domain' if $to !~ /\@/;
1983
$from .= "\@" . $conf->get('HOSTNAME') if $from !~ /\@/;
1984
$to .= '@' . $conf->get('HOSTNAME') if $to !~ /\@/;
1987
$text =~ s/^\.$/../mg;
1988
local $SIG{'PIPE'} = 'IGNORE';
1989
open( PIPE, "| " . $conf->get('MAILPROG') . " -oem $to" )
1990
or die "Can't open pipe to " . $conf->get('MAILPROG') . ": $!\n";
1992
print PIPE "From: $from\n";
1993
print PIPE "Subject: $subject\n\n";
1994
print PIPE "$text\n";
1998
sub db_filename ($) {
2000
return $conf->get('DB_BASE_DIR') . '/' . $conf->get('DB_BASE_NAME') . "-$dist";
2003
# for parsing input to dep-wait
2004
sub parse_deplist ($;$) {
2009
foreach (split( /\s*,\s*/, $deps )) {
2011
# verification requires > starting prompts, no | crap
2012
if (!/^(\S+)\s*(\(\s*(>(?:[>=])?)\s*(\S+)\s*\))?\s*$/) {
2017
my @alts = split( /\s*\|\s*/, $_ );
2018
# Anything with an | is ignored, as it can be configured on a
2019
# per-buildd basis what will be installed
2020
next if $#alts != 0;
2023
if (!/^(\S+)\s*(\(\s*(>=|=|==|>|>>|<<|<=)\s*(\S+)\s*\))?\s*$/) {
2024
warn( "parse_deplist: bad dependency $_\n" );
2027
my($dep, $rel, $relv) = ($1, $3, $4);
2028
$rel = ">>" if defined($rel) and $rel eq ">";
2029
$result{$dep}->{'Package'} = $dep;
2030
if ($rel && $relv) {
2031
$result{$dep}->{'Rel'} = $rel;
2032
$result{$dep}->{'Version'} = $relv;
2035
return 1 if $verify;
2039
# for parsing Build-Depends from Sources
2040
sub parse_srcdeplist ($$$) {
2047
foreach $dep (split( /\s*,\s*/, $deps )) {
2048
my @alts = split( /\s*\|\s*/, $dep );
2049
# Anything with an | is ignored, as it can be configured on a
2050
# per-buildd basis what will be installed
2051
next if $#alts != 0;
2053
if (!/^([^\s([]+)\s*(\(\s*([<=>]+)\s*(\S+)\s*\))?(\s*\[([^]]+)\])?/) {
2054
warn( "parse_srcdeplist: bad dependency $_\n" );
2057
my($dep, $rel, $relv, $archlist) = ($1, $3, $4, $6);
2059
$archlist =~ s/^\s*(.*)\s*$/$1/;
2060
my @archs = split( /\s+/, $archlist );
2061
my ($use_it, $ignore_it, $include) = (0, 0, 0);
2064
$ignore_it = 1 if substr($_, 1) eq $arch;
2066
$use_it = 1 if $_ eq $arch;
2070
warn "Warning: inconsistent arch restriction on ",
2071
"$pkg: $dep depedency\n"
2072
if $ignore_it && $use_it;
2073
next if $ignore_it || ($include && !$use_it);
2081
$result->{'Package'} = $dep;
2082
$result->{'Neg'} = $neg;
2083
if ($rel && $relv) {
2084
$result->{'Rel'} = $rel;
2085
$result->{'Version'} = $relv;
2087
push @results, $result;
2093
sub build_deplist ($) {
2097
foreach $key (keys %$list) {
2098
$result .= ", " if $result;
2100
$result .= " ($list->{$key}->{'Rel'} $list->{$key}->{'Version'})"
2101
if $list->{$key}->{'Rel'} && $list->{$key}->{'Version'};
2106
sub get_unsatisfied_dep ($$$$) {
2110
my $savedep = shift;
2112
my $pkgname = $dep->{'Package'};
2114
if (defined $pkgs->{$pkgname}{'Provider'}) {
2115
# provides. leave them for buildd/sbuild.
2120
return $pkgs->{$pkgname}{'Unsatisfied'} if $savedep and defined($pkgs->{$pkgname}{'Unsatisfied'});
2122
# Return unsatisfied deps to a higher caller to process
2123
if ((!defined($pkgs->{$pkgname})) or
2124
(defined($dep->{'Rel'}) and !version_compare( $pkgs->{$pkgname}{'Version'}, $dep->{'Rel'}, $dep->{'Version'} ) ) ) {
2126
$deplist{$pkgname} = $dep;
2127
my $deps = build_deplist(\%deplist);
2128
$pkgs->{$pkgname}{'Unsatisfied'} = $deps if $savedep;
2132
# set cache to "" to avoid infinite recursion
2133
$pkgs->{$pkgname}{'Unsatisfied'} = "" if $savedep;
2135
if (defined $pkgs->{$dep->{'Package'}}{'Depends'}) {
2136
my $deps = parse_deplist( $pkgs->{$dep->{'Package'}}{'Depends'} );
2137
foreach (keys %$deps) {
2140
my $ret = get_unsatisfied_dep($bd,$pkgs,$dep,1);
2142
my $retdep = parse_deplist( $ret );
2143
foreach (keys %$retdep) {
2144
$dep = $$retdep{$_};
2146
$dep->{'Rel'} = '>=' if defined($dep->{'Rel'}) and $dep->{'Rel'} =~ '^=';
2148
if (defined($dep->{'Rel'}) and $dep->{'Rel'} =~ '^>' and defined ($pkgs->{$dep->{'Package'}}) and
2149
version_compare($bd->{$pkgs->{$dep->{'Package'}}{'Source'}}{'ver'},'>>',$pkgs->{$dep->{'Package'}}{'Sourcev'})) {
2150
if (not defined($merge_binsrc{$dep->{'Package'}})) {
2151
# the uninstallable package doesn't exist in the new source; look for something else that does.
2152
delete $$retdep{$dep->{'Package'}};
2153
foreach (sort (split( /\s*,\s*/, $bd->{$pkgs->{$dep->{'Package'}}{'Source'}}{'bin'}))) {
2154
next if ($pkgs->{$_}{'all'} or not defined $pkgs->{$_}{'Version'});
2155
$dep->{'Package'} = $_;
2156
$dep->{'Rel'} = '>>';
2157
$dep->{'Version'} = $pkgs->{$_}{'Version'};
2158
$$retdep{$_} = $dep;
2163
# sanity check to make sure the depending binary still exists, and the depended binary exists and dep-wait on a new version of it
2164
if ( defined($merge_binsrc{$pkgname}) and defined($pkgs->{$dep->{'Package'}}{'Version'}) ) {
2165
delete $$retdep{$dep->{'Package'}};
2166
$dep->{'Package'} = $pkgname;
2167
$dep->{'Rel'} = '>>';
2168
$dep->{'Version'} = $pkgs->{$pkgname}{'Version'};
2169
$$retdep{$pkgname} = $dep;
2171
delete $$retdep{$dep->{'Package'}} if (defined ($dep->{'Rel'}) and $dep->{'Rel'} =~ '^>');
2174
$ret = build_deplist($retdep);
2175
$pkgs->{$pkgname}{'Unsatisfied'} = $ret if $savedep;
2183
sub auto_dep_wait ($$) {
2188
my $distribution = $conf->get('DISTRIBUTION');
2190
return if (defined ($conf->get('DB_DISTRIBUTIONS')->{'$distribution'}) &&
2191
defined ($conf->get('DB_DISTRIBUTIONS')->{'$distribution'}->{'noadw'}));
2193
# We need to walk all of needs-build, as any new upload could make
2194
# something in needs-build have uninstallable deps
2195
foreach $key ($db->list_packages()) {
2196
my $pkg = $db->get_package($key);
2198
if not defined $pkg or $pkg->{'State'} ne "Needs-Build";
2199
my $srcdeps = parse_srcdeplist($key,$bd->{$key}{'dep'},
2200
$conf->get('ARCH'));
2201
foreach my $srcdep (@$srcdeps) {
2202
next if $srcdep->{'Neg'} != 0; # we ignore conflicts atm
2203
my $rc = get_unsatisfied_dep($bd,$pkgs,$srcdep,0);
2206
my $deplist = parse_deplist( $pkg->{'Depends'} );
2207
my $newdeps = parse_deplist( $rc );
2209
foreach (%$newdeps) {
2210
my $dep = $$newdeps{$_};
2211
# ensure we're not waiting on ourselves, or a package that has been removed
2212
next if (not defined($merge_binsrc{$dep->{'Package'}})) or ($merge_binsrc{$dep->{'Package'}} eq $key);
2213
if ($dep->{'Rel'} =~ '^>') {
2214
$deplist->{$dep->{'Package'}} = $dep;
2219
$pkg->{'Depends'} = build_deplist($deplist);
2220
change_state( $pkg, 'Dep-Wait' );
2221
log_ta( $pkg, "--merge-all" );
2222
$db->set_package($pkg);
2223
print "Auto-Dep-Waiting ${key}_$pkg->{'Version'} to $pkg->{'Depends'}\n" if $conf->get('VERBOSE');
2231
sub pkg_version_eq ($$) {
2233
my $version = shift;
2236
if (defined $pkg->{'Binary-NMU-Version'}) and
2237
version_compare(binNMU_version($pkg->{'Version'},
2238
$pkg->{'Binary-NMU-Version'}),'=', $version);
2239
return version_compare( $pkg->{'Version'}, "=", $version );
75
if (defined($database)) {
76
my $databases = $database->get('Databases');
77
foreach (keys %{$databases}) {
78
$databases->{$_}->close();
79
undef $databases->{$_};