in git-cvsserver.perl [1519:1801]
sub req_ci
{
my ( $cmd, $data ) = @_;
argsplit("ci");
#$log->debug("State : " . Dumper($state));
$log->info("req_ci : " . ( defined($data) ? $data : "[NULL]" ));
if ( $state->{method} eq 'pserver' and $state->{user} eq 'anonymous' )
{
print "error 1 anonymous user cannot commit via pserver\n";
cleanupWorkTree();
exit;
}
if ( -e $state->{CVSROOT} . "/index" )
{
$log->warn("file 'index' already exists in the git repository");
print "error 1 Index already exists in git repo\n";
cleanupWorkTree();
exit;
}
# Grab a handle to the SQLite db and do any necessary updates
my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
$updater->update();
my @committedfiles = ();
my %oldmeta;
my $stickyInfo;
my $branchRef;
my $parenthash;
# foreach file specified on the command line ...
foreach my $filename ( @{$state->{args}} )
{
my $committedfile = $filename;
$filename = filecleanup($filename);
next unless ( exists $state->{entries}{$filename}{modified_filename} or not $state->{entries}{$filename}{unchanged} );
#####
# Figure out which branch and parenthash we are committing
# to, and setup worktree:
# should always come from entries:
my $fileStickyInfo = resolveStickyInfo($filename);
if( !defined($branchRef) )
{
$stickyInfo = $fileStickyInfo;
if( defined($stickyInfo) &&
( defined($stickyInfo->{date}) ||
!defined($stickyInfo->{tag}) ) )
{
print "error 1 cannot commit with sticky date for file `$filename'\n";
cleanupWorkTree();
exit;
}
$branchRef = "refs/heads/$state->{module}";
if ( defined($stickyInfo) && defined($stickyInfo->{tag}) )
{
$branchRef = "refs/heads/$stickyInfo->{tag}";
}
$parenthash = safe_pipe_capture('git', 'show-ref', '-s', $branchRef);
chomp $parenthash;
if ($parenthash !~ /^[0-9a-f]{$state->{hexsz}}$/)
{
if ( defined($stickyInfo) && defined($stickyInfo->{tag}) )
{
print "error 1 sticky tag `$stickyInfo->{tag}' for file `$filename' is not a branch\n";
}
else
{
print "error 1 pserver cannot find the current HEAD of module";
}
cleanupWorkTree();
exit;
}
setupWorkTree($parenthash);
$log->info("Lockless commit start, basing commit on '$work->{workDir}', index file is '$work->{index}'");
$log->info("Created index '$work->{index}' for head $state->{module} - exit status $?");
}
elsif( !refHashEqual($stickyInfo,$fileStickyInfo) )
{
#TODO: We could split the cvs commit into multiple
# git commits by distinct stickyTag values, but that
# is lowish priority.
print "error 1 Committing different files to different"
. " branches is not currently supported\n";
cleanupWorkTree();
exit;
}
#####
# Process this file:
my $meta = $updater->getmeta($filename,$stickyInfo);
$oldmeta{$filename} = $meta;
my $wrev = revparse($filename);
my ( $filepart, $dirpart ) = filenamesplit($filename);
# do a checkout of the file if it is part of this tree
if ($wrev) {
system('git', 'checkout-index', '-f', '-u', $filename);
unless ($? == 0) {
die "Error running git-checkout-index -f -u $filename : $!";
}
}
my $addflag = 0;
my $rmflag = 0;
$rmflag = 1 if ( defined($wrev) and ($wrev=~/^-/) );
$addflag = 1 unless ( -e $filename );
# Do up to date checking
unless ( $addflag or $wrev eq $meta->{revision} or
( $rmflag and $wrev eq "-$meta->{revision}" ) )
{
# fail everything if an up to date check fails
print "error 1 Up to date check failed for $filename\n";
cleanupWorkTree();
exit;
}
push @committedfiles, $committedfile;
$log->info("Committing $filename");
system("mkdir","-p",$dirpart) unless ( -d $dirpart );
unless ( $rmflag )
{
$log->debug("rename $state->{entries}{$filename}{modified_filename} $filename");
rename $state->{entries}{$filename}{modified_filename},$filename;
# Calculate modes to remove
my $invmode = "";
foreach ( qw (r w x) ) { $invmode .= $_ unless ( $state->{entries}{$filename}{modified_mode} =~ /$_/ ); }
$log->debug("chmod u+" . $state->{entries}{$filename}{modified_mode} . "-" . $invmode . " $filename");
system("chmod","u+" . $state->{entries}{$filename}{modified_mode} . "-" . $invmode, $filename);
}
if ( $rmflag )
{
$log->info("Removing file '$filename'");
unlink($filename);
system("git", "update-index", "--remove", $filename);
}
elsif ( $addflag )
{
$log->info("Adding file '$filename'");
system("git", "update-index", "--add", $filename);
} else {
$log->info("UpdatingX2 file '$filename'");
system("git", "update-index", $filename);
}
}
unless ( scalar(@committedfiles) > 0 )
{
print "E No files to commit\n";
print "ok\n";
cleanupWorkTree();
return;
}
my $treehash = safe_pipe_capture(qw(git write-tree));
chomp $treehash;
$log->debug("Treehash : $treehash, Parenthash : $parenthash");
# write our commit message out if we have one ...
my ( $msg_fh, $msg_filename ) = tempfile( DIR => $TEMP_DIR );
print $msg_fh $state->{opt}{m};# if ( exists ( $state->{opt}{m} ) );
if ( defined ( $cfg->{gitcvs}{commitmsgannotation} ) ) {
if ($cfg->{gitcvs}{commitmsgannotation} !~ /^\s*$/ ) {
print $msg_fh "\n\n".$cfg->{gitcvs}{commitmsgannotation}."\n"
}
} else {
print $msg_fh "\n\nvia git-CVS emulator\n";
}
close $msg_fh;
my $commithash = safe_pipe_capture('git', 'commit-tree', $treehash, '-p', $parenthash, '-F', $msg_filename);
chomp($commithash);
$log->info("Commit hash : $commithash");
unless ( $commithash =~ /[a-zA-Z0-9]{$state->{hexsz}}/ )
{
$log->warn("Commit failed (Invalid commit hash)");
print "error 1 Commit failed (unknown reason)\n";
cleanupWorkTree();
exit;
}
### Emulate git-receive-pack by running hooks/update
my @hook = ( $ENV{GIT_DIR}.'hooks/update', $branchRef,
$parenthash, $commithash );
if( -x $hook[0] ) {
unless( system( @hook ) == 0 )
{
$log->warn("Commit failed (update hook declined to update ref)");
print "error 1 Commit failed (update hook declined)\n";
cleanupWorkTree();
exit;
}
}
### Update the ref
if (system(qw(git update-ref -m), "cvsserver ci",
$branchRef, $commithash, $parenthash)) {
$log->warn("update-ref for $state->{module} failed.");
print "error 1 Cannot commit -- update first\n";
cleanupWorkTree();
exit;
}
### Emulate git-receive-pack by running hooks/post-receive
my $hook = $ENV{GIT_DIR}.'hooks/post-receive';
if( -x $hook ) {
open(my $pipe, "| $hook") || die "can't fork $!";
local $SIG{PIPE} = sub { die 'pipe broke' };
print $pipe "$parenthash $commithash $branchRef\n";
close $pipe || die "bad pipe: $! $?";
}
$updater->update();
### Then hooks/post-update
$hook = $ENV{GIT_DIR}.'hooks/post-update';
if (-x $hook) {
system($hook, $branchRef);
}
# foreach file specified on the command line ...
foreach my $filename ( @committedfiles )
{
$filename = filecleanup($filename);
my $meta = $updater->getmeta($filename,$stickyInfo);
unless (defined $meta->{revision}) {
$meta->{revision} = "1.1";
}
my ( $filepart, $dirpart ) = filenamesplit($filename, 1);
$log->debug("Checked-in $dirpart : $filename");
print "M $state->{CVSROOT}/$state->{module}/$filename,v <-- $dirpart$filepart\n";
if ( defined $meta->{filehash} && $meta->{filehash} eq "deleted" )
{
print "M new revision: delete; previous revision: $oldmeta{$filename}{revision}\n";
print "Remove-entry $dirpart\n";
print "$filename\n";
} else {
if ($meta->{revision} eq "1.1") {
print "M initial revision: 1.1\n";
} else {
print "M new revision: $meta->{revision}; previous revision: $oldmeta{$filename}{revision}\n";
}
print "Checked-in $dirpart\n";
print "$filename\n";
my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
print "/$filepart/$meta->{revision}//$kopts/" .
getStickyTagOrDate($stickyInfo) . "\n";
}
}
cleanupWorkTree();
print "ok\n";
}