2010-09-21

Catching Subversion conflicts on commit

If two people work on the same file in the same place in the file, Subversion can get a bit confused about how to merge the two different pieces, and will prompt the user to help it sort things out. However, it is up to the user to actually do so, and they're perfectly able to try to submit that file with the conflict markers still in the file. This is a pre-submit hook to not let people shoot themselves (and your codebase) in the foot.

#!/usr/local/bin/php
<?php
/**
* Pre-commit Subversion script.
* @author Omni Adams <omni@digitaldarkness.com>
*/
/**
* Path to the awk binary.
*/
define('AWK', '/usr/bin/awk');
/**
* Path to the grep binary.
*/
define('GREP', '/bin/grep');
/**
* Path to svnlook binary.
*/
define('SVNLOOK', '/usr/bin/svnlook');
/**
* Divider to inject into error messages.
*/
define('DIVIDER',
'********************************************************************************');
/**
* Scan changed files for SVN conflict markers.
*
* If any of he changed files contain >>>>>>, =======, or
* <<<<<<, writes an error message to standard error and
* returns true.
* @param string $transaction SVN transaction ID.
* @param string $repository Full path to the repository.
* @return boolean True if there was an error.
*/
function catchSvnArtifacts($transaction, $repository) {
$errors = false;
$changedCommand = SVNLOOK . ' changed -t "'
. $transaction . '" "'
. $repository . '" '
. '| ' . GREP . ' "^[UA]" '
. '| ' . AWK . ' \'{print $2}\'';
$changedOutput = array();
exec($changedCommand, $changedOutput);
foreach ($changedOutput as $file) {
$conflicts = '';
$conflictCommand = SVNLOOK . ' cat -t "'
. $transaction . '" "'
. $repository . '" "' . $file . '" '
. '| ' . GREP . ' -E '
. '"(<<<<<<)|(=======)|(>>>>>>)"';
exec($conflictCommand, $conflicts);
if (array() == $conflicts) {
continue;
}
$message = PHP_EOL . DIVIDER . PHP_EOL . PHP_EOL
. $file . ' contains unresolved Subversion '
. 'conflict markers.' . PHP_EOL;
file_put_contents('php://stderr', $message);
$errors = true;
}
return $errors;
}
$repository = $_SERVER['argv'][1];
$transaction = $_SERVER['argv'][2];
if (catchSvnArtifacts($transaction, $repository)) {
exit(1);
}
exit(0);

No comments:

Post a Comment