This is a simple but powerful continuous integration build system for Git. It works by receiving push events from repositories through the post-receive hook, aggregates them on a per-branch basis into a first-come-first-serve build queue, and lets a background build daemon perform builds one at a time. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
		
			
				
	
	
		
			105 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/perl
 | 
						|
#
 | 
						|
# A hook that notifies its companion cidaemon through a simple
 | 
						|
# queue file that a ref has been updated via a push (actually
 | 
						|
# by a receive-pack running on the server).
 | 
						|
#
 | 
						|
# See cidaemon for per-repository configuration details.
 | 
						|
#
 | 
						|
# To use this hook, add it as the post-receive hook, make it
 | 
						|
# executable, and set its configuration options.
 | 
						|
#
 | 
						|
 | 
						|
local $ENV{PATH} = '/opt/git/bin';
 | 
						|
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
use File::Spec;
 | 
						|
use Storable qw(retrieve nstore);
 | 
						|
use Fcntl ':flock';
 | 
						|
 | 
						|
my $git_dir = File::Spec->rel2abs($ENV{GIT_DIR});
 | 
						|
my $queue_name = `git config --get builder.queue`;chop $queue_name;
 | 
						|
$queue_name =~ m,^([^\s]+)$,; $queue_name = $1; # untaint
 | 
						|
unless ($queue_name) {
 | 
						|
	1 while <STDIN>;
 | 
						|
	print STDERR "\nerror: builder.queue not set.  Not enqueing.\n\n";
 | 
						|
	exit;
 | 
						|
}
 | 
						|
my $queue_lock = "$queue_name.lock";
 | 
						|
 | 
						|
my @skip;
 | 
						|
open S, "git config --get-all builder.skip|";
 | 
						|
while (<S>) {
 | 
						|
	chop;
 | 
						|
	push @skip, $_;
 | 
						|
}
 | 
						|
close S;
 | 
						|
 | 
						|
my @new_branch_base;
 | 
						|
open S, "git config --get-all builder.newBranchBase|";
 | 
						|
while (<S>) {
 | 
						|
	chop;
 | 
						|
	push @new_branch_base, $_;
 | 
						|
}
 | 
						|
close S;
 | 
						|
 | 
						|
sub skip ($)
 | 
						|
{
 | 
						|
	local $_ = shift;
 | 
						|
	foreach my $p (@skip) {
 | 
						|
		return 1 if /^$p/;
 | 
						|
	}
 | 
						|
	0;
 | 
						|
}
 | 
						|
 | 
						|
open LOCK, ">$queue_lock" or die "Can't open $queue_lock: $!";
 | 
						|
flock LOCK, LOCK_EX;
 | 
						|
 | 
						|
my $queue = -f $queue_name ? retrieve $queue_name : [];
 | 
						|
my %existing;
 | 
						|
foreach my $r (@$queue) {
 | 
						|
	my ($gd, $ref) = @$r;
 | 
						|
	$existing{$gd}{$ref} = $r;
 | 
						|
}
 | 
						|
 | 
						|
my @new_branch_commits;
 | 
						|
my $loaded_new_branch_commits = 0;
 | 
						|
 | 
						|
while (<STDIN>) {
 | 
						|
	chop;
 | 
						|
	my ($old, $new, $ref) = split / /, $_, 3;
 | 
						|
 | 
						|
	next if $old eq $new;
 | 
						|
	next if $new =~ /^0{40}$/;
 | 
						|
	next if skip $ref;
 | 
						|
 | 
						|
	my $r = $existing{$git_dir}{$ref};
 | 
						|
	if ($r) {
 | 
						|
		$r->[3] = $new;
 | 
						|
	} else {
 | 
						|
		if ($old =~ /^0{40}$/) {
 | 
						|
			if (!$loaded_new_branch_commits && @new_branch_base) {
 | 
						|
				open M,'-|','git','show-ref',@new_branch_base;
 | 
						|
				while (<M>) {
 | 
						|
					($_) = split / /, $_;
 | 
						|
					push @new_branch_commits, $_;
 | 
						|
				}
 | 
						|
				close M;
 | 
						|
				$loaded_new_branch_commits = 1;
 | 
						|
			}
 | 
						|
			$old = [@new_branch_commits];
 | 
						|
		} else {
 | 
						|
			$old = [$old];
 | 
						|
		}
 | 
						|
 | 
						|
		$r = [$git_dir, $ref, $old, $new];
 | 
						|
		$existing{$git_dir}{$ref} = $r;
 | 
						|
		push @$queue, $r;
 | 
						|
	}
 | 
						|
}
 | 
						|
nstore $queue, $queue_name;
 | 
						|
 | 
						|
flock LOCK, LOCK_UN;
 | 
						|
close LOCK;
 |