Quote temp dir in diff command, for windows tempdirs with spaces in them
Quote temp dir in diff command, for windows tempdirs with spaces in them

<?php <?php
/** /**
* GitPHP File Diff * GitPHP File Diff
* *
* Represents a single file difference * Represents a single file difference
* *
* @author Christopher Han <xiphux@gmail.com> * @author Christopher Han <xiphux@gmail.com>
* @copyright Copyright (c) 2010 Christopher Han * @copyright Copyright (c) 2010 Christopher Han
* @package GitPHP * @package GitPHP
* @subpackage Git * @subpackage Git
*/ */
   
require_once(GITPHP_GITOBJECTDIR . 'Blob.class.php'); require_once(GITPHP_GITOBJECTDIR . 'Blob.class.php');
require_once(GITPHP_GITOBJECTDIR . 'TmpDir.class.php'); require_once(GITPHP_GITOBJECTDIR . 'TmpDir.class.php');
require_once(GITPHP_GITOBJECTDIR . 'DiffExe.class.php'); require_once(GITPHP_GITOBJECTDIR . 'DiffExe.class.php');
   
/** /**
* Commit class * Commit class
* *
* @package GitPHP * @package GitPHP
* @subpackage Git * @subpackage Git
*/ */
class GitPHP_FileDiff class GitPHP_FileDiff
{ {
/** /**
* diffInfoRead * diffInfoRead
* *
* Stores whether diff info has been read * Stores whether diff info has been read
* *
* @access protected * @access protected
*/ */
protected $diffInfoRead = false; protected $diffInfoRead = false;
   
/** /**
* diffDataRead * diffDataRead
* *
* Stores whether diff data has been read * Stores whether diff data has been read
* *
* @access protected * @access protected
*/ */
protected $diffDataRead = false; protected $diffDataRead = false;
   
/** /**
* diffData * diffData
* *
* Stores the diff data * Stores the diff data
* *
* @access protected * @access protected
*/ */
protected $diffData; protected $diffData;
   
/** /**
* diffDataSplitRead * diffDataSplitRead
* *
* Stores whether split diff data has been read * Stores whether split diff data has been read
* *
* @access protected * @access protected
*/ */
protected $diffDataSplitRead = false; protected $diffDataSplitRead = false;
   
/** /**
* diffDataSplit * diffDataSplit
* *
* Stores the diff data split up by left/right changes * Stores the diff data split up by left/right changes
* *
* @access protected * @access protected
*/ */
protected $diffDataSplit; protected $diffDataSplit;
   
/** /**
* diffDataName * diffDataName
* *
* Filename used on last data diff * Filename used on last data diff
* *
* @access protected * @access protected
*/ */
protected $diffDataName; protected $diffDataName;
   
/** /**
* fromMode * fromMode
* *
* Stores the from file mode * Stores the from file mode
* *
* @access protected * @access protected
*/ */
protected $fromMode; protected $fromMode;
   
/** /**
* toMode * toMode
* *
* Stores the to file mode * Stores the to file mode
* *
* @access protected * @access protected
*/ */
protected $toMode; protected $toMode;
   
/** /**
* fromHash * fromHash
* *
* Stores the from hash * Stores the from hash
* *
* @access protected * @access protected
*/ */
protected $fromHash; protected $fromHash;
   
/** /**
* toHash * toHash
* *
* Stores the to hash * Stores the to hash
* *
* @access protected * @access protected
*/ */
protected $toHash; protected $toHash;
   
/** /**
* status * status
* *
* Stores the status * Stores the status
* *
* @access protected * @access protected
*/ */
protected $status; protected $status;
   
/** /**
* similarity * similarity
* *
* Stores the similarity * Stores the similarity
* *
* @access protected * @access protected
*/ */
protected $similarity; protected $similarity;
   
/** /**
* fromFile * fromFile
* *
* Stores the from filename * Stores the from filename
* *
* @access protected * @access protected
*/ */
protected $fromFile; protected $fromFile;
   
/** /**
* toFile * toFile
* *
* Stores the to filename * Stores the to filename
* *
* @access protected * @access protected
*/ */
protected $toFile; protected $toFile;
   
/** /**
* fromFileType * fromFileType
* *
* Stores the from file type * Stores the from file type
* *
* @access protected * @access protected
*/ */
protected $fromFileType; protected $fromFileType;
   
/** /**
* toFileType * toFileType
* *
* Stores the to file type * Stores the to file type
* *
* @access protected * @access protected
*/ */
protected $toFileType; protected $toFileType;
   
/** /**
* project * project
* *
* Stores the project * Stores the project
* *
* @access protected * @access protected
*/ */
protected $project; protected $project;
   
/** /**
* commit * commit
* *
* Stores the commit that caused this filediff * Stores the commit that caused this filediff
* *
* @access protected * @access protected
*/ */
protected $commit; protected $commit;
   
/** /**
* __construct * __construct
* *
* Constructor * Constructor
* *
* @access public * @access public
* @param mixed $project project * @param mixed $project project
* @param string $fromHash source hash, can also be a diff-tree info line * @param string $fromHash source hash, can also be a diff-tree info line
* @param string $toHash target hash, required if $fromHash is a hash * @param string $toHash target hash, required if $fromHash is a hash
* @return mixed FileDiff object * @return mixed FileDiff object
* @throws Exception on invalid parameters * @throws Exception on invalid parameters
*/ */
public function __construct($project, $fromHash, $toHash = '') public function __construct($project, $fromHash, $toHash = '')
{ {
$this->project = $project; $this->project = $project;
   
if ($this->ParseDiffTreeLine($fromHash)) if ($this->ParseDiffTreeLine($fromHash))
return; return;
   
if (!(preg_match('/^[0-9a-fA-F]{40}$/', $fromHash) && preg_match('/^[0-9a-fA-F]{40}$/', $toHash))) { if (!(preg_match('/^[0-9a-fA-F]{40}$/', $fromHash) && preg_match('/^[0-9a-fA-F]{40}$/', $toHash))) {
throw new Exception('Invalid parameters for FileDiff'); throw new Exception('Invalid parameters for FileDiff');
} }
   
$this->fromHash = $fromHash; $this->fromHash = $fromHash;
$this->toHash = $toHash; $this->toHash = $toHash;
} }
   
/** /**
* ParseDiffTreeLine * ParseDiffTreeLine
* *
* @access private * @access private
* @param string $diffTreeLine line from difftree * @param string $diffTreeLine line from difftree
* @return boolean true if data was read from line * @return boolean true if data was read from line
*/ */
private function ParseDiffTreeLine($diffTreeLine) private function ParseDiffTreeLine($diffTreeLine)
{ {
if (preg_match('/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/', $diffTreeLine, $regs)) { if (preg_match('/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/', $diffTreeLine, $regs)) {
$this->diffInfoRead = true; $this->diffInfoRead = true;
   
$this->fromMode = $regs[1]; $this->fromMode = $regs[1];
$this->toMode = $regs[2]; $this->toMode = $regs[2];
$this->fromHash = $regs[3]; $this->fromHash = $regs[3];
$this->toHash = $regs[4]; $this->toHash = $regs[4];
$this->status = $regs[5]; $this->status = $regs[5];
$this->similarity = ltrim($regs[6], '0'); $this->similarity = ltrim($regs[6], '0');
$this->fromFile = strtok($regs[7], "\t"); $this->fromFile = strtok($regs[7], "\t");
$this->toFile = strtok("\t"); $this->toFile = strtok("\t");
if ($this->toFile === false) { if ($this->toFile === false) {
/* no filename change */ /* no filename change */
$this->toFile = $this->fromFile; $this->toFile = $this->fromFile;
} }
   
return true; return true;
} }
   
return false; return false;
} }
   
/** /**
* ReadDiffInfo * ReadDiffInfo
* *
* Reads file diff info * Reads file diff info
* *
* @access protected * @access protected
*/ */
protected function ReadDiffInfo() protected function ReadDiffInfo()
{ {
$this->diffInfoRead = true; $this->diffInfoRead = true;
   
/* TODO: read a single difftree line on-demand */ /* TODO: read a single difftree line on-demand */
} }
   
/** /**
* GetFromMode * GetFromMode
* *
* Gets the from file mode * Gets the from file mode
* (full a/u/g/o) * (full a/u/g/o)
* *
* @access public * @access public
* @return string from file mode * @return string from file mode
*/ */
public function GetFromMode() public function GetFromMode()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->fromMode; return $this->fromMode;
} }
   
/** /**
* GetFromModeShort * GetFromModeShort
* *
* Gets the from file mode in short form * Gets the from file mode in short form
* (standard u/g/o) * (standard u/g/o)
* *
* @access public * @access public
* @return string short from file mode * @return string short from file mode
*/ */
public function GetFromModeShort() public function GetFromModeShort()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return substr($this->fromMode, -4); return substr($this->fromMode, -4);
} }
   
/** /**
* GetToMode * GetToMode
* *
* Gets the to file mode * Gets the to file mode
* (full a/u/g/o) * (full a/u/g/o)
* *
* @access public * @access public
* @return string to file mode * @return string to file mode
*/ */
public function GetToMode() public function GetToMode()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->toMode; return $this->toMode;
} }
   
/** /**
* GetToModeShort * GetToModeShort
* *
* Gets the to file mode in short form * Gets the to file mode in short form
* (standard u/g/o) * (standard u/g/o)
* *
* @access public * @access public
* @return string short to file mode * @return string short to file mode
*/ */
public function GetToModeShort() public function GetToModeShort()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return substr($this->toMode, -4); return substr($this->toMode, -4);
} }
   
/** /**
* GetFromHash * GetFromHash
* *
* Gets the from hash * Gets the from hash
* *
* @access public * @access public
* @return string from hash * @return string from hash
*/ */
public function GetFromHash() public function GetFromHash()
{ {
return $this->fromHash; return $this->fromHash;
} }
   
/** /**
* GetToHash * GetToHash
* *
* Gets the to hash * Gets the to hash
* *
* @access public * @access public
* @return string to hash * @return string to hash
*/ */
public function GetToHash() public function GetToHash()
{ {
return $this->toHash; return $this->toHash;
} }
   
/** /**
* GetFromBlob * GetFromBlob
* *
* Gets the from file blob * Gets the from file blob
* *
* @access public * @access public
* @return mixed blob object * @return mixed blob object
*/ */
public function GetFromBlob() public function GetFromBlob()
{ {
if (empty($this->fromHash)) if (empty($this->fromHash))
return null; return null;
   
return $this->project->GetBlob($this->fromHash); return $this->project->GetBlob($this->fromHash);
} }
   
/** /**
* GetToBlob * GetToBlob
* *
* Gets the to file blob * Gets the to file blob
* *
* @access public * @access public
* @return mixed blob object * @return mixed blob object
*/ */
public function GetToBlob() public function GetToBlob()
{ {
if (empty($this->toHash)) if (empty($this->toHash))
return null; return null;
   
return $this->project->GetBlob($this->toHash); return $this->project->GetBlob($this->toHash);
} }
   
/** /**
* GetStatus * GetStatus
* *
* Gets the status of the change * Gets the status of the change
* *
* @access public * @access public
* @return string status * @return string status
*/ */
public function GetStatus() public function GetStatus()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->status; return $this->status;
} }
   
/** /**
* GetSimilarity * GetSimilarity
* *
* Gets the similarity * Gets the similarity
* *
* @access public * @access public
* @return string similarity * @return string similarity
*/ */
public function GetSimilarity() public function GetSimilarity()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->similarity; return $this->similarity;
} }
   
/** /**
* GetFromFile * GetFromFile
* *
* Gets the from file name * Gets the from file name
* *
* @access public * @access public
* @return string from file * @return string from file
*/ */
public function GetFromFile() public function GetFromFile()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->fromFile; return $this->fromFile;
} }
   
/** /**
* GetToFile * GetToFile
* *
* Gets the to file name * Gets the to file name
* *
* @access public * @access public
* @return string to file * @return string to file
*/ */
public function GetToFile() public function GetToFile()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return $this->toFile; return $this->toFile;
} }
   
/** /**
* GetFromFileType * GetFromFileType
* *
* Gets the from file type * Gets the from file type
* *
* @access public * @access public
* @param boolean $local true if caller wants localized type * @param boolean $local true if caller wants localized type
* @return string from file type * @return string from file type
*/ */
public function GetFromFileType($local = false) public function GetFromFileType($local = false)
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return GitPHP_Blob::FileType($this->fromMode, $local); return GitPHP_Blob::FileType($this->fromMode, $local);
} }
   
/** /**
* GetToFileType * GetToFileType
* *
* Gets the to file type * Gets the to file type
* *
* @access public * @access public
* @param boolean $local true if caller wants localized type * @param boolean $local true if caller wants localized type
* @return string to file type * @return string to file type
*/ */
public function GetToFileType($local = false) public function GetToFileType($local = false)
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return GitPHP_Blob::FileType($this->toMode, $local); return GitPHP_Blob::FileType($this->toMode, $local);
} }
   
/** /**
* FileTypeChanged * FileTypeChanged
* *
* Tests if filetype changed * Tests if filetype changed
* *
* @access public * @access public
* @return boolean true if file type changed * @return boolean true if file type changed
*/ */
public function FileTypeChanged() public function FileTypeChanged()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return (octdec($this->fromMode) & 0x17000) != (octdec($this->toMode) & 0x17000); return (octdec($this->fromMode) & 0x17000) != (octdec($this->toMode) & 0x17000);
} }
   
/** /**
* FileModeChanged * FileModeChanged
* *
* Tests if file mode changed * Tests if file mode changed
* *
* @access public * @access public
* @return boolean true if file mode changed * @return boolean true if file mode changed
*/ */
public function FileModeChanged() public function FileModeChanged()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return (octdec($this->fromMode) & 0777) != (octdec($this->toMode) & 0777); return (octdec($this->fromMode) & 0777) != (octdec($this->toMode) & 0777);
} }
   
/** /**
* FromFileIsRegular * FromFileIsRegular
* *
* Tests if the from file is a regular file * Tests if the from file is a regular file
* *
* @access public * @access public
* @return boolean true if from file is regular * @return boolean true if from file is regular
*/ */
public function FromFileIsRegular() public function FromFileIsRegular()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return (octdec($this->fromMode) & 0x8000) == 0x8000; return (octdec($this->fromMode) & 0x8000) == 0x8000;
} }
   
/** /**
* ToFileIsRegular * ToFileIsRegular
* *
* Tests if the to file is a regular file * Tests if the to file is a regular file
* *
* @access public * @access public
* @return boolean true if to file is regular * @return boolean true if to file is regular
*/ */
public function ToFileIsRegular() public function ToFileIsRegular()
{ {
if (!$this->diffInfoRead) if (!$this->diffInfoRead)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
return (octdec($this->toMode) & 0x8000) == 0x8000; return (octdec($this->toMode) & 0x8000) == 0x8000;
} }
   
/** /**
* GetDiff * GetDiff
* *
* Gets the diff output * Gets the diff output
* *
* @access public * @access public
* @param string $file override the filename on the diff * @param string $file override the filename on the diff
* @return string diff output * @return string diff output
*/ */
public function GetDiff($file = '', $readFileData = true, $explode = false) public function GetDiff($file = '', $readFileData = true, $explode = false)
{ {
if ($this->diffDataRead && ($file == $this->diffDataName)) { if ($this->diffDataRead && ($file == $this->diffDataName)) {
if ($explode) if ($explode)
return explode("\n", $this->diffData); return explode("\n", $this->diffData);
else else
return $this->diffData; return $this->diffData;
} }
   
if ((!$this->diffInfoRead) && $readFileData) if ((!$this->diffInfoRead) && $readFileData)
$this->ReadDiffInfo(); $this->ReadDiffInfo();
   
$this->diffDataName = $file; $this->diffDataName = $file;
$this->diffDataRead = true; $this->diffDataRead = true;
   
if ((!empty($this->status)) && ($this->status != 'A') && ($this->status != 'D') && ($this->status != 'M')) { if ((!empty($this->status)) && ($this->status != 'A') && ($this->status != 'D') && ($this->status != 'M')) {
$this->diffData = ''; $this->diffData = '';
return; return;
} }
   
$tmpdir = GitPHP_TmpDir::GetInstance(); $tmpdir = GitPHP_TmpDir::GetInstance();
   
$pid = 0; $pid = 0;
if (function_exists('posix_getpid')) if (function_exists('posix_getpid'))
$pid = posix_getpid(); $pid = posix_getpid();
else else
$pid = rand(); $pid = rand();
   
$fromTmpFile = null; $fromTmpFile = null;
$toTmpFile = null; $toTmpFile = null;
   
$fromName = null; $fromName = null;
$toName = null; $toName = null;
   
if ((empty($this->status)) || ($this->status == 'D') || ($this->status == 'M')) { if ((empty($this->status)) || ($this->status == 'D') || ($this->status == 'M')) {
$fromBlob = $this->GetFromBlob(); $fromBlob = $this->GetFromBlob();
$fromTmpFile = 'gitphp_' . $pid . '_from'; $fromTmpFile = 'gitphp_' . $pid . '_from';
$tmpdir->AddFile($fromTmpFile, $fromBlob->GetData()); $tmpdir->AddFile($fromTmpFile, $fromBlob->GetData());
   
$fromName = 'a/'; $fromName = 'a/';
if (!empty($file)) { if (!empty($file)) {
$fromName .= $file; $fromName .= $file;
} else if (!empty($this->fromFile)) { } else if (!empty($this->fromFile)) {
$fromName .= $this->fromFile; $fromName .= $this->fromFile;
} else { } else {
$fromName .= $this->fromHash; $fromName .= $this->fromHash;
} }
} }
   
if ((empty($this->status)) || ($this->status == 'A') || ($this->status == 'M')) { if ((empty($this->status)) || ($this->status == 'A') || ($this->status == 'M')) {
$toBlob = $this->GetToBlob(); $toBlob = $this->GetToBlob();
$toTmpFile = 'gitphp_' . $pid . '_to'; $toTmpFile = 'gitphp_' . $pid . '_to';
$tmpdir->AddFile($toTmpFile, $toBlob->GetData()); $tmpdir->AddFile($toTmpFile, $toBlob->GetData());
   
$toName = 'b/'; $toName = 'b/';
if (!empty($file)) { if (!empty($file)) {
$toName .= $file; $toName .= $file;
} else if (!empty($this->toFile)) { } else if (!empty($this->toFile)) {
$toName .= $this->toFile; $toName .= $this->toFile;
} else { } else {
$toName .= $this->toHash; $toName .= $this->toHash;
} }
} }
   
$this->diffData = GitPHP_DiffExe::Diff((empty($fromTmpFile) ? null : ($tmpdir->GetDir() . $fromTmpFile)), $fromName, (empty($toTmpFile) ? null : ($tmpdir->GetDir() . $toTmpFile)), $toName); $this->diffData = GitPHP_DiffExe::Diff((empty($fromTmpFile) ? null : escapeshellarg($tmpdir->GetDir() . $fromTmpFile)), $fromName, (empty($toTmpFile) ? null : escapeshellarg($tmpdir->GetDir() . $toTmpFile)), $toName);
   
if (!empty($fromTmpFile)) { if (!empty($fromTmpFile)) {
$tmpdir->RemoveFile($fromTmpFile); $tmpdir->RemoveFile($fromTmpFile);
} }
   
if (!empty($toTmpFile)) { if (!empty($toTmpFile)) {
$tmpdir->RemoveFile($toTmpFile); $tmpdir->RemoveFile($toTmpFile);
} }
   
if ($explode) if ($explode)
return explode("\n", $this->diffData); return explode("\n", $this->diffData);
else else
return $this->diffData; return $this->diffData;
} }
   
/** /**
* GetDiffSplit * GetDiffSplit
* *
* construct the side by side diff data from the git data * construct the side by side diff data from the git data
* The result is an array of ternary arrays with 3 elements each: * The result is an array of ternary arrays with 3 elements each:
* First the mode ("" or "-added" or "-deleted" or "-modified"), * First the mode ("" or "-added" or "-deleted" or "-modified"),
* then the first column, then the second. * then the first column, then the second.
* *
* @author Mattias Ulbrich * @author Mattias Ulbrich
* *
* @access public * @access public
* @return an array of line elements (see above) * @return an array of line elements (see above)
*/ */
public function GetDiffSplit() public function GetDiffSplit()
{ {
if ($this->diffDataSplitRead) { if ($this->diffDataSplitRead) {
return $this->diffDataSplit; return $this->diffDataSplit;
} }
   
$this->diffDataSplitRead = true; $this->diffDataSplitRead = true;
   
$exe = new GitPHP_GitExe($this->project); $exe = new GitPHP_GitExe($this->project);
   
$rawBlob = $exe->Execute(GIT_CAT_FILE, $rawBlob = $exe->Execute(GIT_CAT_FILE,
array("blob", $this->fromHash)); array("blob", $this->fromHash));
$blob = explode("\n", $rawBlob); $blob = explode("\n", $rawBlob);
   
$diffLines = explode("\n", $exe->Execute(GIT_DIFF, $diffLines = explode("\n", $exe->Execute(GIT_DIFF,
array("-U0", $this->fromHash, array("-U0", $this->fromHash,
$this->toHash))); $this->toHash)));
   
unset($exe); unset($exe);
   
// //
// parse diffs // parse diffs
$diffs = array(); $diffs = array();
$currentDiff = FALSE; $currentDiff = FALSE;
foreach($diffLines as $d) { foreach($diffLines as $d) {
if(strlen($d) == 0) if(strlen($d) == 0)
continue; continue;
switch($d[0]) { switch($d[0]) {
case '@': case '@':
if($currentDiff) { if($currentDiff) {
if (count($currentDiff['left']) == 0 && count($currentDiff['right']) > 0) if (count($currentDiff['left']) == 0 && count($currentDiff['right']) > 0)
$currentDiff['line']++; // HACK to make added blocks align correctly $currentDiff['line']++; // HACK to make added blocks align correctly
$diffs[] = $currentDiff; $diffs[] = $currentDiff;
} }
$comma = strpos($d, ","); $comma = strpos($d, ",");
$line = -intval(substr($d, 2, $comma-2)); $line = -intval(substr($d, 2, $comma-2));
$currentDiff = array("line" => $line, $currentDiff = array("line" => $line,
"left" => array(), "right" => array()); "left" => array(), "right" => array());
break; break;
case '+': case '+':
if($currentDiff) if($currentDiff)
$currentDiff["right"][] = substr($d, 1); $currentDiff["right"][] = substr($d, 1);
break; break;
case '-': case '-':
if($currentDiff) if($currentDiff)
$currentDiff["left"][] = substr($d, 1); $currentDiff["left"][] = substr($d, 1);
break; break;
case ' ': case ' ':
echo "should not happen!"; echo "should not happen!";
if($currentDiff) { if($currentDiff) {
$currentDiff["left"][] = substr($d, 1); $currentDiff["left"][] = substr($d, 1);
$currentDiff["right"][] = substr($d, 1); $currentDiff["right"][] = substr($d, 1);
} }
break; break;
} }
} }
if($currentDiff) { if($currentDiff) {
if (count($currentDiff['left']) == 0 && count($currentDiff['right']) > 0) if (count($currentDiff['left']) == 0 && count($currentDiff['right']) > 0)
$currentDiff['line']++; // HACK to make added blocks align correctly $currentDiff['line']++; // HACK to make added blocks align correctly
$diffs[] = $currentDiff; $diffs[] = $currentDiff;
} }
   
// //
// iterate over diffs // iterate over diffs
$output = array(); $output = array();
$idx = 0; $idx = 0;
foreach($diffs as $d) { foreach($diffs as $d) {
while($idx+1 < $d['line']) { while($idx+1 < $d['line']) {
$h = $blob[$idx]; $h = $blob[$idx];
$output[] = array('', $h, $h); $output[] = array('', $h, $h);
$idx ++; $idx ++;
} }
   
if(count($d['left']) == 0) { if(count($d['left']) == 0) {
$mode = 'added'; $mode = 'added';
} elseif(count($d['right']) == 0) { } elseif(count($d['right']) == 0) {
$mode = 'deleted'; $mode = 'deleted';
} else { } else {
$mode = 'modified'; $mode = 'modified';
} }
   
for($i = 0; $i < count($d['left']) || $i < count($d['right']); $i++) { for($i = 0; $i < count($d['left']) || $i < count($d['right']); $i++) {
$left = $i < count($d['left']) ? $d['left'][$i] : FALSE; $left = $i < count($d['left']) ? $d['left'][$i] : FALSE;
$right = $i < count($d['right']) ? $d['right'][$i] : FALSE; $right = $i < count($d['right']) ? $d['right'][$i] : FALSE;
$output[] = array($mode, $left, $right); $output[] = array($mode, $left, $right);
} }
   
$idx += count($d['left']); $idx += count($d['left']);
} }
   
while($idx < count($blob)) { while($idx < count($blob)) {
$h = $blob[$idx]; $h = $blob[$idx];
$output[] = array('', $h, $h); $output[] = array('', $h, $h);
$idx ++; $idx ++;
} }
   
$this->diffDataSplit = $output; $this->diffDataSplit = $output;
return $output; return $output;
} }
   
/** /**
* GetCommit * GetCommit
* *
* Gets the commit for this filediff * Gets the commit for this filediff
* *
* @access public * @access public
* @return commit object * @return commit object
*/ */
public function GetCommit() public function GetCommit()
{ {
return $this->commit; return $this->commit;
} }
   
/** /**
* SetCommit * SetCommit
* *
* Sets the commit for this filediff * Sets the commit for this filediff
* *
* @access public * @access public
* @param mixed $commit commit object * @param mixed $commit commit object
*/ */
public function SetCommit($commit) public function SetCommit($commit)
{ {
$this->commit = $commit; $this->commit = $commit;
} }
} }
   
comments