+ if (defined $pkg->{'binary_nmu_version'}) and
+ version_compare(binNMU_version($pkg->{'version'},
+ $pkg->{'binary_nmu_version'}),'=', $version);
+ return version_compare( $pkg->{'version'}, "=", $version );
+}
+
+sub table_name {
+ return '"' . $arch . $schema_suffix . '".packages';
+}
+
+sub user_table_name {
+ return '"' . $arch . $schema_suffix . '".users';
+}
+
+sub transactions_table_name {
+ return '"' . $arch . $schema_suffix . '".transactions';
+}
+
+sub pkg_history_table_name {
+ return '"' . $arch . $schema_suffix . '".pkg_history';
+}
+
+sub get_readonly_source_info {
+ my $name = shift;
+ # SELECT FLOOR(EXTRACT('epoch' FROM age(localtimestamp, '2010-01-22 23:45')) / 86400) -- change to that?
+ my $q = "SELECT rel, priority, state_change, permbuildpri, section, buildpri, failed, state, binary_nmu_changelog, bd_problem, version, package, distribution, installed_version, notes, failed_category, builder, old_failed, previous_state, binary_nmu_version, depends, extract(days from date_trunc('days', now() - state_change)) as state_days"
+ . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution AND result = 'successful') AS successtime"
+ . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution ) AS anytime"
+ . " FROM " . table_name()
+ . ' WHERE package = ? AND distribution = ?';
+ my $pkg = $dbh->selectrow_hashref( $q,
+ undef, $name, $distribution);
+ return $pkg;
+}
+
+sub get_source_info {
+ my $name = shift;
+ return get_readonly_source_info($name) if $simulate;
+ my $pkg = $dbh->selectrow_hashref('SELECT *, extract(days from date_trunc(\'days\', now() - state_change)) as state_days FROM ' .
+ table_name() . ' WHERE package = ? AND distribution = ?' .
+ ' FOR UPDATE',
+ undef, $name, $distribution);
+ return $pkg;
+}
+
+sub get_all_source_info {
+ my %options = @_;
+
+ my $q = "SELECT rel, priority, state_change, permbuildpri, section, buildpri, failed, state, binary_nmu_changelog, bd_problem, version, package, distribution, installed_version, notes, failed_category, builder, old_failed, previous_state, binary_nmu_version, depends, extract(days from date_trunc('days', now() - state_change)) as state_days"
+# . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution AND result = 'successful') AS successtime"
+# . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution ) AS anytime"
+ . ", successtime.build_time as successtime, anytime.build_time as anytime"
+ . " FROM " . table_name()
+ . " left join ( "
+ . "select distinct on (package, distribution) build_time, package, distribution from ".pkg_history_table_name()." where result = 'successful' order by package, distribution, timestamp "
+ . " ) as successtime using (package, distribution) "
+ . " left join ( "
+ . "select distinct on (package, distribution) build_time, package, distribution from ".pkg_history_table_name()." order by package, distribution, timestamp desc"
+ . " ) as anytime using (package, distribution) "
+ . " WHERE TRUE ";
+ my @args = ();
+ if ($distribution) {
+ my @dists = split(/[, ]+/, $distribution);
+ $q .= ' AND ( distribution = ? '.(' OR distribution = ? ' x $#dists).' )';
+ foreach my $d ( @dists ) {
+ push @args, ($d);
+ }
+ }
+ if ($options{state} && uc($options{state}) ne "ALL") {
+ $q .= ' AND upper(state) = ? ';
+ push @args, uc($options{state});
+ }
+
+ if ($options{user} && uc($options{state}) ne "NEEDS-BUILD") { # if it's NEEDS-BUILD, we don't look at users
+ #this basically means "this user, or no user at all":
+ $q .= " AND (builder = ? OR upper(state) = 'NEEDS-BUILD')";
+ push @args, $options{user};
+ }
+
+ if ($options{category}) {
+ $q .= ' AND failed_category <> ? AND upper(state) = ? ';
+ push @args, $options{category};
+ push @args, "FAILED";
+ }
+
+ if ($options{list_min_age} > 0) {
+ $q .= ' AND age(state_change) > ? ';
+ push @args, $options{list_min_age} . " days";
+ }
+
+ if ($options{list_min_age} < 0) {
+ $q .= ' AND age(state_change) < ? ';
+ push @args, -$options{list_min_age} . " days";
+ }
+
+ my $db = $dbh->selectall_hashref($q, 'package', undef, @args);
+ return $db;
+}
+
+sub update_source_info {
+ my $pkg = shift;
+ return if $simulate;
+
+ my $pkg2 = get_source_info($pkg->{'package'});
+ if (! defined $pkg2)
+ {
+ add_source_info($pkg);
+ }
+
+ $dbh->do('UPDATE ' . table_name() . ' SET ' .
+ 'version = ?, ' .
+ 'state = ?, ' .
+ 'section = ?, ' .
+ 'priority = ?, ' .
+ 'installed_version = ?, ' .
+ 'previous_state = ?, ' .
+ (($pkg->{'do_state_change'}) ? "state_change = now()," : "").
+ 'notes = ?, ' .
+ 'builder = ?, ' .
+ 'failed = ?, ' .
+ 'old_failed = ?, ' .
+ 'binary_nmu_version = ?, ' .
+ 'binary_nmu_changelog = ?, ' .
+ 'failed_category = ?, ' .
+ 'permbuildpri = ?, ' .
+ 'buildpri = ?, ' .
+ 'depends = ?, ' .
+ 'rel = ?, ' .
+ 'bd_problem = ? ' .
+ 'WHERE package = ? AND distribution = ?',
+ undef,
+ $pkg->{'version'},
+ $pkg->{'state'},
+ $pkg->{'section'},
+ $pkg->{'priority'},
+ $pkg->{'installed_version'},
+ $pkg->{'previous_state'},
+ $pkg->{'notes'},
+ $pkg->{'builder'},
+ $pkg->{'failed'},
+ $pkg->{'old_failed'},
+ $pkg->{'binary_nmu_version'},
+ $pkg->{'binary_nmu_changelog'},
+ $pkg->{'failed_category'},
+ $pkg->{'permbuildpri'},
+ $pkg->{'buildpri'},
+ $pkg->{'depends'},
+ $pkg->{'rel'},
+ $pkg->{'bd_problem'},
+ $pkg->{'package'},
+ $distribution) or die $dbh->errstr;
+}
+
+sub add_source_info {
+ return if $simulate;
+ my $pkg = shift;
+ $dbh->do('INSERT INTO ' . table_name() .
+ ' (package, distribution) values (?, ?)',
+ undef, $pkg->{'package'}, $distribution) or die $dbh->errstr;
+}
+
+sub del_source_info {
+ return if $simulate;
+ my $name = shift;
+ $dbh->do('DELETE FROM ' . table_name() .
+ ' WHERE package = ? AND distribution = ?',
+ undef, $name, $distribution) or die $dbh->errstr;
+}
+
+sub get_user_info {
+ my $name = shift;
+ my $user = $dbh->selectrow_hashref('SELECT * FROM ' .
+ user_table_name() . ' WHERE username = ? AND distribution = ?',
+ undef, $name, $distribution);
+ return $user;
+}
+
+sub update_user_info {
+ return if $simulate;
+ my $user = shift;
+ $dbh->do('UPDATE ' . user_table_name() .
+ ' SET last_seen = now() WHERE username = ?' .
+ ' AND distribution = ?',
+ undef, $user, $distribution)
+ or die $dbh->errstr;
+}
+
+
+sub add_user_info {
+ return if $simulate;
+ my $user = shift;
+ $dbh->do('INSERT INTO ' . user_table_name() .
+ ' (username, distribution, last_seen)' .
+ ' values (?, ?, now())',
+ undef, $user, $distribution)
+ or die $dbh->errstr;
+}
+
+sub lock_table()
+{
+ return if $simulate;
+ $dbh->do('LOCK TABLE ' . table_name() .
+ ' IN EXCLUSIVE MODE', undef) or die $dbh->errstr;
+}
+
+sub parse_argv() {
+# parts the array $_[0] and $_[1] and returns the sub-array (modifies the original one)
+ my @ret = ();
+ my $args = shift;
+ my $separator = shift;
+ while($args->[0] && $args->[0] ne $separator) {
+ push @ret, shift @$args;
+ }
+ shift @$args if @$args;
+ return @ret;
+}
+
+sub parse_all_v3() {
+ my $srcs = shift;
+ my $db = get_all_source_info();
+ my $binary = $srcs->{'_binary'};
+
+ SRCS:
+ foreach my $name (keys %$srcs) {
+ next if $name eq '_binaries';
+
+ # state = installed, out-of-date, uncompiled, not-for-us
+ my $pkgs = $srcs->{$name};
+ my $pkg = $db->{$name};
+
+ unless ($pkg) {
+ next SRCS if $pkgs->{'status'} eq 'not-for-us';
+
+ # does at least one binary exist in the database and is more recent - if so, we're probably just outdated, ignore the source package
+ for my $bin (@{$pkgs->{'binary'}}) {
+ if ($binary->{$bin} and vercmp($pkgs->{'version'}, $binary->{$bin}) < 0) {
+ print "merge-v3: skiping $name ($arch)\n" if $verbose || $simulate;
+ next SRCS;
+ }
+ }
+ $pkg->{'package'} = $name;
+ }
+
+ if (isin($pkgs->{'status'}, qw (installed, related)) && $pkg->{'binary_nmu_version'} && $pkgs->{'binnmu'} < $pkg->{'binary_nmu_version'}) {
+ $pkgs->{'status'} = 'out-of-date';
+ }
+ if (isin($pkgs->{'status'}, qw (installed, related))) {
+ if ($pkg->{'state'} ne 'Installed') {
+ change_state( \$pkg, 'Installed');
+ $pkg->{'version'} = $pkgs->{'version'};
+ $pkg->{'installed_version'} = $pkgs->{'version'};
+ $pkg->{'binary_nmu_version'} = $pkgs->{'binnmu'};
+ $pkg->{'section'} = $pkgs->{'section'};
+ $pkg->{'priority'} = $pkgs->{'priority'};
+ if (isin($pkgs->{'status'}, qw (related))) {
+ $pkg->{'notes'} = "related";
+ }
+ print "merge-v3: set $name ($arch) to installed/".$pkg->{'notes'}."\n" if $verbose || $simulate;
+ log_ta( $pkg, "--merge-v3: installed" ) unless $simulate;
+ update_source_info($pkg) unless $simulate;
+ }
+ next;
+ }
+
+ if ($pkgs->{'status'} eq 'not-for-us') {
+ next if isin( $pkg->{'state'}, qw(Not-For-Us Installed Failed-Removed));
+
+ if (isin( $pkg->{'state'}, qw(Failed Build-Attempted Built))) {
+ change_state( \$pkg, "Failed-Removed" );
+ log_ta( $pkg, "--merge-v3: Failed-Removed" ) unless $simulate;
+ update_source_info($pkg) unless $simulate;
+ print "$name ($pkg->{'version'}): (virtually) deleted from database\n" if $verbose || $simulate;
+ next;
+ }
+
+ print "should delete $name (not-for-us)\n" if $verbose || $simulate || 1; # not implemented yet on purpose
+ next;
+ }
+
+ # only uncompiled / out-of-date are left, so check if anything new
+ next if $pkgs->{'version'} eq $pkg->{'version'};
+
+ print "should set $name to needs-builds\n" if $simulate;
+ if (defined( $pkg->{'state'} ) && isin( $pkg->{'state'}, qw(Building Built Build-Attempted))) {
+ send_mail( $pkg->{'builder'},
+ "new version of $name (dist=$distribution)",
+ "As far as I'm informed, you're currently building the package $name\n".
+ "in version $pkg->{'version'}.\n\n".
+ "Now there's a new source version $pkgs->{'version'}. If you haven't finished\n".
+ "compiling $name yet, you can stop it to save some work.\n".
+ "Just to inform you...\n".
+ "(This is an automated message)\n" ) unless $simulate;
+ print "$name: new version ($pkgs->{'version'}) while building $pkg->{'version'} -- sending mail to builder ($pkg->{'builder'})\n"
+ if $verbose || $simulate;
+ }
+ change_state( \$pkg, 'Needs-Build');
+ $pkg->{'notes'} = $pkgs->{'status'};
+ $pkg->{'version'} = $pkgs->{'version'};
+ $pkg->{'section'} = $pkgs->{'section'};
+ $pkg->{'priority'} = $pkgs->{'priority'};
+ $pkg->{'dep'} = $pkgs->{'depends'};
+ $pkg->{'conf'} = $pkgs->{'conflicts'};
+ delete $pkg->{'builder'};
+ delete $pkg->{'binary_nmu_version'};
+ delete $pkg->{'binary_nmu_changelog'};
+ log_ta( $pkg, "--merge-v3: needs-build" ) unless $simulate;
+ update_source_info($pkg) unless $simulate;
+ print "$name ($pkgs->{'version'} / $arch) needs rebuilding now.\n" if $verbose || $simulate;
+ }
+
+ foreach my $name (keys %$db) {
+ next if $srcs->{$name};
+ my $pkg = $db->{$name};
+ # package disappeared - delete
+ change_state( \$pkg, 'deleted' );
+ log_ta( $pkg, "--merge-v3: deleted" ) unless $simulate;
+ print "$name ($pkg->{'version'} / $arch) deleted from database\n" if $verbose || $simulate;
+ del_source_info($name) unless $simulate;
+ delete $db->{$name};
+ }