*/␊ |
class IDF_Diff␊ |
{␊ |
public $repo = '';␊ |
public $diff = '';␊ |
public $path_strip_level = 0;␊ |
protected $lines = array();␊ |
␊ |
public $files = array();␊ |
␊ |
public function __construct($diff, $repo='')␊ |
public function __construct($diff, $path_strip_level = 0)␊ |
{␊ |
$this->repo = $repo;␊ |
$this->diff = $diff;␊ |
$this->path_strip_level = $path_strip_level;␊ |
$this->lines = preg_split("/\015\012|\015|\012/", $diff);␊ |
}␊ |
␊ |
|
$files = array();␊ |
$indiff = false; // Used to skip the headers in the git patches␊ |
$i = 0; // Used to skip the end of a git patch with --\nversion number␊ |
foreach ($this->lines as $line) {␊ |
$i++;␊ |
if (0 === strpos($line, '--') and isset($this->lines[$i])␊ |
and preg_match('/^\d+\.\d+\.\d+\.\d+$/', $this->lines[$i])) {␊ |
break;␊ |
}␊ |
if (0 === strpos($line, 'diff --git a')) {␊ |
$current_file = self::getFile($line);␊ |
$files[$current_file] = array();␊ |
$files[$current_file]['chunks'] = array();␊ |
$files[$current_file]['chunks_def'] = array();␊ |
$current_chunk = 0;␊ |
$indiff = true;␊ |
continue;␊ |
} else if (preg_match('#^diff -r [^\s]+ -r [^\s]+ (.+)$#', $line, $matches)) {␊ |
$current_file = $matches[1];␊ |
$files[$current_file] = array();␊ |
$files[$current_file]['chunks'] = array();␊ |
$files[$current_file]['chunks_def'] = array();␊ |
$current_chunk = 0;␊ |
$indiff = true;␊ |
continue;␊ |
} else if (!$indiff && 0 === strpos($line, '=========')) {␊ |
// ignore pseudo stanzas with a hint of a binary file␊ |
if (preg_match("/^# (.+) is binary/", $this->lines[$i]))␊ |
continue;␊ |
// by default always use the new name of a possibly renamed file␊ |
$current_file = self::getMtnFile($this->lines[$i+1]);␊ |
// mtn 0.48 and newer set /dev/null as file path for dropped files␊ |
// so we display the old name here␊ |
if ($current_file == "/dev/null") {␊ |
$current_file = self::getMtnFile($this->lines[$i]);␊ |
}␊ |
if ($current_file == "/dev/null") {␊ |
throw new Exception(␊ |
"could not determine path from diff"␊ |
);␊ |
}␊ |
$files[$current_file] = array();␊ |
$files[$current_file]['chunks'] = array();␊ |
$files[$current_file]['chunks_def'] = array();␊ |
$current_chunk = 0;␊ |
$indiff = true;␊ |
continue;␊ |
} else if (0 === strpos($line, 'Index: ')) {␊ |
$current_file = self::getSvnFile($line);␊ |
$files[$current_file] = array();␊ |
$files[$current_file]['chunks'] = array();␊ |
$files[$current_file]['chunks_def'] = array();␊ |
$current_chunk = 0;␊ |
$indiff = true;␊ |
continue;␊ |
}␊ |
if (!$indiff) {␊ |
continue;␊ |
}␊ |
if (0 === strpos($line, '@@ ')) {␊ |
$files[$current_file]['chunks_def'][] = self::getChunk($line);␊ |
$files[$current_file]['chunks'][] = array();␊ |
$current_chunk++;␊ |
$lline = $files[$current_file]['chunks_def'][$current_chunk-1][0][0];␊ |
$rline = $files[$current_file]['chunks_def'][$current_chunk-1][1][0];␊ |
continue;␊ |
}␊ |
if (0 === strpos($line, '---') or 0 === strpos($line, '+++')) {␊ |
$diffsize = count($this->lines);␊ |
while ($i < $diffsize) {␊ |
// look for the potential beginning of a diff␊ |
if (substr($this->lines[$i], 0, 4) !== '--- ') {␊ |
$i++;␊ |
continue;␊ |
}␊ |
if (0 === strpos($line, '-')) {␊ |
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, '', substr($line, 1));␊ |
$lline++;␊ |
␊ |
// we're inside a diff candiate␊ |
$oldfileline = $this->lines[$i++];␊ |
$newfileline = $this->lines[$i++];␊ |
if (substr($newfileline, 0, 4) !== '+++ ') {␊ |
// not a valid diff here, move on␊ |
continue;␊ |
}␊ |
if (0 === strpos($line, '+')) {␊ |
$files[$current_file]['chunks'][$current_chunk-1][] = array('', $rline, substr($line, 1));␊ |
$rline++;␊ |
continue;␊ |
␊ |
// use new file name by default␊ |
preg_match("/^\+\+\+ ([^\t]+)/", $newfileline, $m);␊ |
$current_file = $m[1];␊ |
if ($current_file === '/dev/null') {␊ |
// except if it's /dev/null, use the old one instead␊ |
// eg. mtn 0.48 and newer␊ |
preg_match("/^--- ([^\t]+)/", $oldfileline, $m);␊ |
$current_file = $m[1];␊ |
}␊ |
if (0 === strpos($line, ' ')) {␊ |
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, $rline, substr($line, 1));␊ |
$rline++;␊ |
$lline++;␊ |
continue;␊ |
if ($this->path_strip_level > 0) {␊ |
$current_file = array_pop(explode('/', $current_file, $this->path_strip_level+1));␊ |
}␊ |
if ($line == '') {␊ |
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, $rline, $line);␊ |
$rline++;␊ |
$lline++;␊ |
continue;␊ |
$current_chunk = 0;␊ |
$files[$current_file] = array();␊ |
$files[$current_file]['chunks'] = array();␊ |
$files[$current_file]['chunks_def'] = array();␊ |
␊ |
while ($i < $diffsize && substr($this->lines[$i], 0, 3) === '@@ ') {␊ |
$elems = preg_match('/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@.*/',␊ |
$this->lines[$i++], $results);␊ |
if ($elems != 1) {␊ |
// hunk is badly formatted␊ |
break;␊ |
}␊ |
$delstart = $results[1];␊ |
$dellines = $results[2] === '' ? 1 : $results[2];␊ |
$addstart = $results[3];␊ |
$addlines = $results[4] === '' ? 1 : $results[4];␊ |
$chunks_def = array(array($delstart), array($addstart));␊ |
if ($results[2] != '') $chunks_def[0][] = $dellines;␊ |
if ($results[4] != '') $chunks_def[1][] = $addlines;␊ |
$files[$current_file]['chunks_def'][] = $chunks_def;␊ |
$files[$current_file]['chunks'][] = array();␊ |
␊ |
while ($addlines >= 0 || $dellines >= 0) {␊ |
$linetype = $this->lines[$i] != '' ? $this->lines[$i][0] : ' ';␊ |
switch ($linetype) {␊ |
case ' ':␊ |
$files[$current_file]['chunks'][$current_chunk][] =␊ |
array($delstart, $addstart, substr($this->lines[$i++], 1));␊ |
$dellines--;␊ |
$addlines--;␊ |
$delstart++;␊ |
$addstart++;␊ |
break;␊ |
case '+':␊ |
$files[$current_file]['chunks'][$current_chunk][] =␊ |
array('', $addstart, substr($this->lines[$i++], 1));␊ |
$addlines--;␊ |
$addstart++;␊ |
break;␊ |
case '-':␊ |
$files[$current_file]['chunks'][$current_chunk][] =␊ |
array($delstart, '', substr($this->lines[$i++], 1));␊ |
$dellines--;␊ |
$delstart++;␊ |
break;␊ |
default:␊ |
break 2;␊ |
}␊ |
}␊ |
$current_chunk++;␊ |
}␊ |
}␊ |
$this->files = $files;␊ |
return $files;␊ |
}␊ |
␊ |
public static function getFile($line)␊ |
{␊ |
$line = substr(trim($line), 10);␊ |
$n = (int) strlen($line)/2;␊ |
return trim(substr($line, 3, $n-3));␊ |
}␊ |
␊ |
public static function getSvnFile($line)␊ |
{␊ |
return substr(trim($line), 7);␊ |
}␊ |
␊ |
public static function getMtnFile($line)␊ |
{␊ |
preg_match("/^[+-]{3} ([^\t]+)/", $line, $m);␊ |
return $m[1];␊ |
}␊ |
␊ |
/**␊ |
* Return the html version of a parsed diff.␊ |
*/␊ |
|
return Pluf_Template::markSafe($out);␊ |
}␊ |
␊ |
␊ |
public static function padLine($line)␊ |
{␊ |
$line = str_replace("\t", ' ', $line);␊ |
|
}␊ |
␊ |
/**␊ |
* @return array array(array(start, n), array(start, n))␊ |
*/␊ |
public static function getChunk($line)␊ |
{␊ |
$elts = explode(' ', $line);␊ |
$res = array();␊ |
for ($i=1;$i<3;$i++) {␊ |
$res[] = explode(',', trim(substr($elts[$i], 1)));␊ |
}␊ |
return $res;␊ |
}␊ |
␊ |
/**␊ |
* Review patch.␊ |
*␊ |
* Given the original file as a string and the parsed␊ |
|
return $nnew_chunks;␊ |
}␊ |
␊ |
␊ |
public function renderCompared($chunks, $filename)␊ |
{␊ |
$fileinfo = IDF_FileUtil::getMimeType($filename);␊ |
|
$i++;␊ |
}␊ |
return Pluf_Template::markSafe($out);␊ |
␊ |
}␊ |
}␊ |