#! /usr/bin/env perl use strict; use utf8; use Hydra::Plugin; use Hydra::Helper::Nix; use Hydra::Helper::AddBuilds; use IO::Select; STDERR->autoflush(1); binmode STDERR, ":encoding(utf8)"; my $config = getHydraConfig(); my $db = Hydra::Model::DB->new(); my @plugins = Hydra::Plugin->instantiate(db => $db, config => $config); my $dbh = $db->storage->dbh; $dbh->do("listen build_started"); $dbh->do("listen build_finished"); $dbh->do("listen step_finished"); sub buildStarted { my ($buildId) = @_; my $build = $db->resultset('Builds')->find($buildId) or die "build $buildId does not exist\n"; foreach my $plugin (@plugins) { eval { $plugin->buildStarted($build); }; if ($@) { print STDERR "$plugin->buildStarted: $@\n"; } } } sub buildFinished { my ($build, @deps) = @_; my $project = $build->project; my $jobset = $build->jobset; if (length($project->declfile) && $jobset->name eq ".jobsets" && $build->iscurrent) { handleDeclarativeJobsetBuild($db, $project, $build); } my @dependents; foreach my $id (@deps) { my $dep = $db->resultset('Builds')->find($id) or die "build $id does not exist\n"; push @dependents, $dep; } foreach my $plugin (@plugins) { eval { $plugin->buildFinished($build, [@dependents]); }; if ($@) { print STDERR "$plugin->buildFinished: $@\n"; } } $build->update({ notificationpendingsince => undef }); } sub stepFinished { my ($buildId, $stepNr, $logPath) = @_; my $build = $db->resultset('Builds')->find($buildId) or die "build $buildId does not exist\n"; my $step = $build->buildsteps->find({stepnr => $stepNr}) or die "step $stepNr does not exist\n"; $logPath = undef if $logPath eq "-"; foreach my $plugin (@plugins) { eval { $plugin->stepFinished($step, $logPath); }; if ($@) { print STDERR "$plugin->stepFinished: $@\n"; } } } # Process builds that finished while hydra-notify wasn't running. for my $build ($db->resultset('Builds')->search( { notificationpendingsince => { '!=', undef } })) { my $buildId = $build->id; print STDERR "sending notifications for build ${\$buildId}...\n"; buildFinished($build); } # Process incoming notifications. my $fd = $dbh->func("getfd"); my $sel = IO::Select->new($fd); while (1) { $sel->can_read; my $notify = $dbh->func("pg_notifies"); next if !$notify; my ($channelName, $pid, $payload) = @$notify; #print STDERR "got '$channelName' from $pid: $payload\n"; my @payload = split /\t/, $payload; eval { if ($channelName eq "build_started") { buildStarted(int($payload[0])); } elsif ($channelName eq "build_finished") { my $buildId = int($payload[0]); my $build = $db->resultset('Builds')->find($buildId) or die "build $buildId does not exist\n"; buildFinished($build, @payload[1..$#payload]); } elsif ($channelName eq "step_finished") { stepFinished(int($payload[0]), int($payload[1])); } }; if ($@) { print STDERR "error processing message '$payload' on channel '$channelName': $@\n"; } }