Load blob data from pack
Load blob data from pack

<?php <?php
/** /**
* GitPHP Blob * GitPHP Blob
* *
* Represents a single blob * Represents a single blob
* *
* @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 . 'FilesystemObject.class.php'); require_once(GITPHP_GITOBJECTDIR . 'FilesystemObject.class.php');
require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php'); require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php');
   
/** /**
* Commit class * Commit class
* *
* @package GitPHP * @package GitPHP
* @subpackage Git * @subpackage Git
*/ */
class GitPHP_Blob extends GitPHP_FilesystemObject class GitPHP_Blob extends GitPHP_FilesystemObject
{ {
   
/** /**
* data * data
* *
* Stores the file data * Stores the file data
* *
* @access protected * @access protected
*/ */
protected $data; protected $data;
   
/** /**
* dataRead * dataRead
* *
* Stores whether data has been read * Stores whether data has been read
* *
* @access protected * @access protected
*/ */
protected $dataRead = false; protected $dataRead = false;
   
/** /**
* size * size
* *
* Stores the size * Stores the size
* *
* @access protected * @access protected
*/ */
protected $size; protected $size;
   
/** /**
* history * history
* *
* Stores the history * Stores the history
* *
* @access protected * @access protected
*/ */
protected $history = array(); protected $history = array();
   
/** /**
* historyRead * historyRead
* *
* Stores whether the history has been read * Stores whether the history has been read
* *
* @access protected * @access protected
*/ */
protected $historyRead = false; protected $historyRead = false;
   
/** /**
* blame * blame
* *
* Stores blame info * Stores blame info
* *
* @access protected * @access protected
*/ */
protected $blame = array(); protected $blame = array();
   
/** /**
* blameRead * blameRead
* *
* Stores whether blame was read * Stores whether blame was read
* *
* @access protected * @access protected
*/ */
protected $blameRead = false; protected $blameRead = false;
   
/** /**
* __construct * __construct
* *
* Instantiates object * Instantiates object
* *
* @access public * @access public
* @param mixed $project the project * @param mixed $project the project
* @param string $hash object hash * @param string $hash object hash
* @return mixed blob object * @return mixed blob object
* @throws Exception exception on invalid hash * @throws Exception exception on invalid hash
*/ */
public function __construct($project, $hash) public function __construct($project, $hash)
{ {
parent::__construct($project, $hash); parent::__construct($project, $hash);
} }
   
/** /**
* GetData * GetData
* *
* Gets the blob data * Gets the blob data
* *
* @access public * @access public
* @param boolean $explode true to explode data into an array of lines * @param boolean $explode true to explode data into an array of lines
* @return string blob data * @return string blob data
*/ */
public function GetData($explode = false) public function GetData($explode = false)
{ {
if (!$this->dataRead) if (!$this->dataRead)
$this->ReadData(); $this->ReadData();
   
if ($explode) if ($explode)
return explode("\n", $this->data); return explode("\n", $this->data);
else else
return $this->data; return $this->data;
} }
   
/** /**
* ReadData * ReadData
* *
* Reads the blob data * Reads the blob data
* *
* @access private * @access private
*/ */
private function ReadData() private function ReadData()
{ {
$this->dataRead = true; $this->dataRead = true;
   
$exe = new GitPHP_GitExe($this->GetProject()); if (GitPHP_Config::GetInstance()->GetValue('compat', false)) {
  $exe = new GitPHP_GitExe($this->GetProject());
$args = array();  
$args[] = 'blob'; $args = array();
$args[] = $this->hash; $args[] = 'blob';
  $args[] = $this->hash;
$this->data = $exe->Execute(GIT_CAT_FILE, $args);  
  $this->data = $exe->Execute(GIT_CAT_FILE, $args);
  } else {
  $this->data = $this->GetProject()->GetObject($this->hash);
  }
   
GitPHP_Cache::GetInstance()->Set($this->GetCacheKey(), $this); GitPHP_Cache::GetInstance()->Set($this->GetCacheKey(), $this);
} }
   
/** /**
* FileType * FileType
* *
* Gets a file type from its octal mode * Gets a file type from its octal mode
* *
* @access public * @access public
* @static * @static
* @param string $octMode octal mode * @param string $octMode octal mode
* @param boolean $local true if caller wants localized type * @param boolean $local true if caller wants localized type
* @return string file type * @return string file type
*/ */
public static function FileType($octMode, $local = false) public static function FileType($octMode, $local = false)
{ {
$mode = octdec($octMode); $mode = octdec($octMode);
if (($mode & 0x4000) == 0x4000) { if (($mode & 0x4000) == 0x4000) {
if ($local) { if ($local) {
return __('directory'); return __('directory');
} else { } else {
return 'directory'; return 'directory';
} }
} else if (($mode & 0xA000) == 0xA000) { } else if (($mode & 0xA000) == 0xA000) {
if ($local) { if ($local) {
return __('symlink'); return __('symlink');
} else { } else {
return 'symlink'; return 'symlink';
} }
} else if (($mode & 0x8000) == 0x8000) { } else if (($mode & 0x8000) == 0x8000) {
if ($local) { if ($local) {
return __('file'); return __('file');
} else { } else {
return 'file'; return 'file';
} }
} }
   
if ($local) { if ($local) {
return __('unknown'); return __('unknown');
} else { } else {
return 'unknown'; return 'unknown';
} }
} }
   
/** /**
* GetSize * GetSize
* *
* Gets the blob size * Gets the blob size
* *
* @access public * @access public
* @return integer size * @return integer size
*/ */
public function GetSize() public function GetSize()
{ {
return $this->size; return $this->size;
} }
   
/** /**
* SetSize * SetSize
* *
* Sets the blob size * Sets the blob size
* *
* @access public * @access public
* @param integer $size size * @param integer $size size
*/ */
public function SetSize($size) public function SetSize($size)
{ {
$this->size = $size; $this->size = $size;
} }
   
/** /**
* FileMime * FileMime
* *
* Get the file mimetype * Get the file mimetype
* *
* @access public * @access public
* @param boolean $short true to only the type group * @param boolean $short true to only the type group
* @return string mime * @return string mime
*/ */
public function FileMime($short = false) public function FileMime($short = false)
{ {
$mime = $this->FileMime_Fileinfo(); $mime = $this->FileMime_Fileinfo();
   
if (empty($mime)) if (empty($mime))
$mime = $this->FileMime_File(); $mime = $this->FileMime_File();
   
if (empty($mime)) if (empty($mime))
$mime = $this->FileMime_Extension(); $mime = $this->FileMime_Extension();
   
if ((!empty($mime)) && $short) { if ((!empty($mime)) && $short) {
$mime = strtok($mime, '/'); $mime = strtok($mime, '/');
} }
   
return $mime; return $mime;
} }
   
/** /**
* FileMime_Fileinfo * FileMime_Fileinfo
* *
* Get the file mimetype using fileinfo * Get the file mimetype using fileinfo
* *
* @access private * @access private
* @return string mimetype * @return string mimetype
*/ */
private function FileMime_Fileinfo() private function FileMime_Fileinfo()
{ {
if (!function_exists('finfo_buffer')) if (!function_exists('finfo_buffer'))
return ''; return '';
   
if (!$this->dataRead) if (!$this->dataRead)
$this->ReadData(); $this->ReadData();
   
if (!$this->data) if (!$this->data)
return ''; return '';
   
$mime = ''; $mime = '';
   
$magicdb = GitPHP_Config::GetInstance()->GetValue('magicdb', null); $magicdb = GitPHP_Config::GetInstance()->GetValue('magicdb', null);
if (empty($magicdb)) { if (empty($magicdb)) {
if (GitPHP_Util::IsWindows()) { if (GitPHP_Util::IsWindows()) {
$magicdb = 'C:\\wamp\\php\\extras\\magic'; $magicdb = 'C:\\wamp\\php\\extras\\magic';
} else { } else {
$magicdb = '/usr/share/misc/magic'; $magicdb = '/usr/share/misc/magic';
} }
} }
   
$finfo = finfo_open(FILEINFO_MIME, $magicdb); $finfo = finfo_open(FILEINFO_MIME, $magicdb);
if ($finfo) { if ($finfo) {
$mime = finfo_buffer($finfo, $this->data, FILEINFO_MIME); $mime = finfo_buffer($finfo, $this->data, FILEINFO_MIME);
if ($mime && strpos($mime, '/')) { if ($mime && strpos($mime, '/')) {
if (strpos($mime, ';')) { if (strpos($mime, ';')) {
$mime = strtok($mime, ';'); $mime = strtok($mime, ';');
} }
} }
finfo_close($finfo); finfo_close($finfo);
} }
   
return $mime; return $mime;
} }
   
/** /**
* FileMime_File * FileMime_File
* *
* Get the file mimetype using file command * Get the file mimetype using file command
* *
* @access private * @access private
* @return string mimetype * @return string mimetype
*/ */
private function FileMime_File() private function FileMime_File()
{ {
if (GitPHP_Util::IsWindows()) { if (GitPHP_Util::IsWindows()) {
return ''; return '';
} }
   
if (!$this->dataRead) if (!$this->dataRead)
$this->ReadData(); $this->ReadData();
   
if (!$this->data) if (!$this->data)
return ''; return '';
   
$descspec = array( $descspec = array(
0 => array('pipe', 'r'), 0 => array('pipe', 'r'),
1 => array('pipe', 'w') 1 => array('pipe', 'w')
); );
   
$proc = proc_open('file -b --mime -', $descspec, $pipes); $proc = proc_open('file -b --mime -', $descspec, $pipes);
if (is_resource($proc)) { if (is_resource($proc)) {
fwrite($pipes[0], $this->data); fwrite($pipes[0], $this->data);
fclose($pipes[0]); fclose($pipes[0]);
$mime = stream_get_contents($pipes[1]); $mime = stream_get_contents($pipes[1]);
fclose($pipes[1]); fclose($pipes[1]);
proc_close($proc); proc_close($proc);
   
if ($mime && strpos($mime, '/')) { if ($mime && strpos($mime, '/')) {
if (strpos($mime, ';')) { if (strpos($mime, ';')) {
$mime = strtok($mime, ';'); $mime = strtok($mime, ';');
} }
return $mime; return $mime;
} }
} }
   
return ''; return '';
} }
   
/** /**
* FileMime_Extension * FileMime_Extension
* *
* Get the file mimetype using the file extension * Get the file mimetype using the file extension
* *
* @access private * @access private
* @return string mimetype * @return string mimetype
*/ */
private function FileMime_Extension() private function FileMime_Extension()
{ {
$file = $this->GetName(); $file = $this->GetName();
   
if (empty($file)) if (empty($file))
return ''; return '';
   
$dotpos = strrpos($file, '.'); $dotpos = strrpos($file, '.');
if ($dotpos !== FALSE) if ($dotpos !== FALSE)
$file = substr($file, $dotpos+1); $file = substr($file, $dotpos+1);
switch ($file) { switch ($file) {
case 'jpg': case 'jpg':
case 'jpeg': case 'jpeg':
case 'jpe': case 'jpe':
return 'image/jpeg'; return 'image/jpeg';
break; break;
case 'gif': case 'gif':
return 'image/gif'; return 'image/gif';
break; break;
case 'png'; case 'png';
return 'image/png'; return 'image/png';
break; break;
} }
   
return ''; return '';
} }
   
/** /**
* GetHistory * GetHistory
* *
* Gets the history of this file * Gets the history of this file
* *
* @access public * @access public
* @return array array of filediff changes * @return array array of filediff changes
*/ */
public function GetHistory() public function GetHistory()
{ {
if (!$this->historyRead) if (!$this->historyRead)
$this->ReadHistory(); $this->ReadHistory();
   
return $this->history; return $this->history;
} }
   
/** /**
* ReadHistory * ReadHistory
* *
* Reads the file history * Reads the file history
* *
* @access private * @access private
*/ */
private function ReadHistory() private function ReadHistory()
{ {
$this->historyRead = true; $this->historyRead = true;
   
$exe = new GitPHP_GitExe($this->GetProject()); $exe = new GitPHP_GitExe($this->GetProject());
$args = array(); $args = array();
if (isset($this->commit)) if (isset($this->commit))
$args[] = $this->commit->GetHash(); $args[] = $this->commit->GetHash();
else else
$args[] = 'HEAD'; $args[] = 'HEAD';
$args[] = '|'; $args[] = '|';
$args[] = $exe->GetBinary(); $args[] = $exe->GetBinary();
$args[] = '--git-dir=' . $this->GetProject()->GetPath(); $args[] = '--git-dir=' . $this->GetProject()->GetPath();
$args[] = GIT_DIFF_TREE; $args[] = GIT_DIFF_TREE;
$args[] = '-r'; $args[] = '-r';
$args[] = '--stdin'; $args[] = '--stdin';
$args[] = '--'; $args[] = '--';
$args[] = $this->GetPath(); $args[] = $this->GetPath();
$historylines = explode("\n", $exe->Execute(GIT_REV_LIST, $args)); $historylines = explode("\n", $exe->Execute(GIT_REV_LIST, $args));
   
$commit = null; $commit = null;
foreach ($historylines as $line) { foreach ($historylines as $line) {
if (preg_match('/^([0-9a-fA-F]{40})/', $line, $regs)) { if (preg_match('/^([0-9a-fA-F]{40})/', $line, $regs)) {
$commit = $this->GetProject()->GetCommit($regs[1]); $commit = $this->GetProject()->GetCommit($regs[1]);
} else if ($commit) { } else if ($commit) {
try { try {
$history = new GitPHP_FileDiff($this->GetProject(), $line); $history = new GitPHP_FileDiff($this->GetProject(), $line);
$history->SetCommit($commit); $history->SetCommit($commit);
$this->history[] = $history; $this->history[] = $history;
} catch (Exception $e) { } catch (Exception $e) {
} }
unset ($commit); unset ($commit);
} }
} }
} }
   
/** /**
* GetBlame * GetBlame
* *
* Gets blame info * Gets blame info
* *
* @access public * @access public
* @return array blame array (line to commit mapping) * @return array blame array (line to commit mapping)
*/ */
public function GetBlame() public function GetBlame()
{ {
if (!$this->blameRead) if (!$this->blameRead)
$this->ReadBlame(); $this->ReadBlame();
   
return $this->blame; return $this->blame;
} }
   
/** /**
* ReadBlame * ReadBlame
* *
* Read blame info * Read blame info
* *
* @access private * @access private
*/ */
private function ReadBlame() private function ReadBlame()
{ {
$this->blameRead = true; $this->blameRead = true;
   
$exe = new GitPHP_GitExe($this->GetProject()); $exe = new GitPHP_GitExe($this->GetProject());
   
$args = array(); $args = array();
$args[] = '-s'; $args[] = '-s';
$args[] = '-l'; $args[] = '-l';
if ($this->commit) if ($this->commit)
$args[] = $this->commit->GetHash(); $args[] = $this->commit->GetHash();
else else
$args[] = 'HEAD'; $args[] = 'HEAD';
$args[] = '--'; $args[] = '--';
$args[] = $this->GetPath(); $args[] = $this->GetPath();
   
$blamelines = explode("\n", $exe->Execute(GIT_BLAME, $args)); $blamelines = explode("\n", $exe->Execute(GIT_BLAME, $args));
   
$lastcommit = ''; $lastcommit = '';
foreach ($blamelines as $line) { foreach ($blamelines as $line) {
if (preg_match('/^([0-9a-fA-F]{40})(\s+.+)?\s+([0-9]+)\)/', $line, $regs)) { if (preg_match('/^([0-9a-fA-F]{40})(\s+.+)?\s+([0-9]+)\)/', $line, $regs)) {
if ($regs[1] != $lastcommit) { if ($regs[1] != $lastcommit) {
$this->blame[(int)($regs[3])] = $this->GetProject()->GetCommit($regs[1]); $this->blame[(int)($regs[3])] = $this->GetProject()->GetCommit($regs[1]);
$lastcommit = $regs[1]; $lastcommit = $regs[1];
} }
} }
} }
} }
   
/** /**
* __sleep * __sleep
* *
* Called to prepare the object for serialization * Called to prepare the object for serialization
* *
* @access public * @access public
* @return array list of properties to serialize * @return array list of properties to serialize
*/ */
public function __sleep() public function __sleep()
{ {
$properties = array('data', 'dataRead'); $properties = array('data', 'dataRead');
   
return array_merge($properties, parent::__sleep()); return array_merge($properties, parent::__sleep());
} }
   
/** /**
* GetCacheKey * GetCacheKey
* *
* Gets the cache key to use for this object * Gets the cache key to use for this object
* *
* @access public * @access public
* @return string cache key * @return string cache key
*/ */
public function GetCacheKey() public function GetCacheKey()
{ {
$key = parent::GetCacheKey(); $key = parent::GetCacheKey();
if (!empty($key)) if (!empty($key))
$key .= '|'; $key .= '|';
   
$key .= 'blob|' . $this->hash; $key .= 'blob|' . $this->hash;
   
return $key; return $key;
} }
   
} }
   
comments