PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/include/git/Archive.class.php

http://github.com/tpruvot/GitPHP
PHP | 559 lines | 239 code | 74 blank | 246 comment | 47 complexity | 19e70140716fdc6ee4c065d98c12ec75 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * GitPHP Archive
  4. *
  5. * Represents an archive (snapshot)
  6. *
  7. * @author Christopher Han <xiphux@gmail.com>
  8. * @copyright Copyright (c) 2010 Christopher Han
  9. * @package GitPHP
  10. * @subpackage Git
  11. */
  12. require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php');
  13. require_once(GITPHP_GITOBJECTDIR . 'Commit.class.php');
  14. define('GITPHP_COMPRESS_TAR', 'tar');
  15. define('GITPHP_COMPRESS_BZ2', 'tbz2');
  16. define('GITPHP_COMPRESS_GZ', 'tgz');
  17. define('GITPHP_COMPRESS_ZIP', 'zip');
  18. /**
  19. * Archive class
  20. *
  21. * @package GitPHP
  22. * @subpackage Git
  23. */
  24. class GitPHP_Archive
  25. {
  26. /**
  27. * objectType
  28. *
  29. * Stores the object type for this archive
  30. *
  31. * @access protected
  32. */
  33. protected $objectType;
  34. /**
  35. * objectHash
  36. *
  37. * Stores the object hash for this archive
  38. *
  39. * @access protected
  40. */
  41. protected $objectHash;
  42. /**
  43. * project
  44. *
  45. * Stores the project for this archive internally
  46. *
  47. * @access protected
  48. */
  49. protected $project;
  50. /**
  51. * format
  52. *
  53. * Stores the archive format internally
  54. *
  55. * @access protected
  56. */
  57. protected $format;
  58. /**
  59. * fileName
  60. *
  61. * Stores the archive filename internally
  62. *
  63. * @access protected
  64. */
  65. protected $fileName = '';
  66. /**
  67. * path
  68. *
  69. * Stores the archive path internally
  70. *
  71. * @access protected
  72. */
  73. protected $path = '';
  74. /**
  75. * prefix
  76. *
  77. * Stores the archive prefix internally
  78. *
  79. * @access protected
  80. */
  81. protected $prefix = '';
  82. /**
  83. * handle
  84. *
  85. * Stores the process handle
  86. *
  87. * @access protected
  88. */
  89. protected $handle = false;
  90. /**
  91. * tempfile
  92. *
  93. * Stores the temp file name
  94. *
  95. * @access protected
  96. */
  97. protected $tempfile = '';
  98. /**
  99. * __construct
  100. *
  101. * Instantiates object
  102. *
  103. * @access public
  104. * @param mixed $gitObject the object
  105. * @param integer $format the format for the archive
  106. * @return mixed git archive
  107. */
  108. public function __construct($project, $gitObject, $format = GITPHP_FORMAT_ZIP, $path = '', $prefix = '')
  109. {
  110. $this->SetProject($project);
  111. $this->SetObject($gitObject);
  112. if (!$this->project && $gitObject) {
  113. $this->project = $gitObject->GetProject()->GetProject();
  114. }
  115. $this->SetFormat($format);
  116. $this->SetPath($path);
  117. $this->SetPrefix($prefix);
  118. }
  119. /**
  120. * GetFormat
  121. *
  122. * Gets the archive format
  123. *
  124. * @access public
  125. * @return integer archive format
  126. */
  127. public function GetFormat()
  128. {
  129. return $this->format;
  130. }
  131. /**
  132. * SetFormat
  133. *
  134. * Sets the archive format
  135. *
  136. * @access public
  137. * @param integer $format archive format
  138. */
  139. public function SetFormat($format)
  140. {
  141. if ((($format == GITPHP_COMPRESS_BZ2) && (!function_exists('bzcompress'))) ||
  142. (($format == GITPHP_COMPRESS_GZ) && (!function_exists('gzencode')))) {
  143. /*
  144. * Trying to set a format but doesn't have the appropriate
  145. * compression function, fall back to tar
  146. */
  147. $format = GITPHP_COMPRESS_TAR;
  148. }
  149. $this->format = $format;
  150. }
  151. /**
  152. * GetObject
  153. *
  154. * Gets the object for this archive
  155. *
  156. * @access public
  157. * @return mixed the git object
  158. */
  159. public function GetObject()
  160. {
  161. if ($this->objectType == 'commit') {
  162. return $this->GetProject()->GetCommit($this->objectHash);
  163. }
  164. if ($this->objectType = 'tree') {
  165. return $this->GetProject()->GetTree($this->objectHash);
  166. }
  167. return null;
  168. }
  169. /**
  170. * SetObject
  171. *
  172. * Sets the object for this archive
  173. *
  174. * @access public
  175. * @param mixed $object the git object
  176. */
  177. public function SetObject($object)
  178. {
  179. // Archive only works for commits and trees
  180. if ($object == null) {
  181. $this->objectHash = '';
  182. $this->objectType = '';
  183. return;
  184. }
  185. if ($object instanceof GitPHP_Commit) {
  186. $this->objectType = 'commit';
  187. $this->objectHash = $object->GetHash();
  188. return;
  189. }
  190. if ($object instanceof GitPHP_Tree) {
  191. $this->objectType = 'tree';
  192. $this->objectHash = $object->GetHash();
  193. return;
  194. }
  195. throw new Exception('Invalid source object for archive');
  196. }
  197. /**
  198. * GetProject
  199. *
  200. * Gets the project for this archive
  201. *
  202. * @access public
  203. * @return mixed the project
  204. */
  205. public function GetProject()
  206. {
  207. if ($this->project)
  208. return GitPHP_ProjectList::GetInstance()->GetProject($this->project);
  209. return null;
  210. }
  211. /**
  212. * SetProject
  213. *
  214. * Sets the project for this archive
  215. *
  216. * @access public
  217. * @param mixed $project the project
  218. */
  219. public function SetProject($project)
  220. {
  221. if ($project)
  222. $this->project = $project->GetProject();
  223. else
  224. $this->project = null;
  225. }
  226. /**
  227. * GetExtension
  228. *
  229. * Gets the extension to use for this archive
  230. *
  231. * @access public
  232. * @return string extension for the archive
  233. */
  234. public function GetExtension()
  235. {
  236. return GitPHP_Archive::FormatToExtension($this->format);
  237. }
  238. /**
  239. * GetFilename
  240. *
  241. * Gets the filename for this archive
  242. *
  243. * @access public
  244. * @return string filename
  245. */
  246. public function GetFilename()
  247. {
  248. if (!empty($this->fileName)) {
  249. return $this->fileName;
  250. }
  251. $fname = $this->GetProject()->GetSlug();
  252. if (!empty($this->path)) {
  253. $fname .= '-' . GitPHP_Util::MakeSlug($this->path);
  254. }
  255. if (!empty($this->objectHash)) {
  256. $fname .= '-' . $this->GetProject()->AbbreviateHash($this->objectHash);
  257. }
  258. $fname .= '.' . $this->GetExtension();
  259. return $fname;
  260. }
  261. /**
  262. * SetFilename
  263. *
  264. * Sets the filename for this archive
  265. *
  266. * @access public
  267. * @param string $name filename
  268. */
  269. public function SetFilename($name = '')
  270. {
  271. $this->fileName = $name;
  272. }
  273. /**
  274. * GetPath
  275. *
  276. * Gets the path to restrict this archive to
  277. *
  278. * @access public
  279. * @return string path
  280. */
  281. public function GetPath()
  282. {
  283. return $this->path;
  284. }
  285. /**
  286. * SetPath
  287. *
  288. * Sets the path to restrict this archive to
  289. *
  290. * @access public
  291. * @param string $path path to restrict
  292. */
  293. public function SetPath($path = '')
  294. {
  295. $this->path = $path;
  296. }
  297. /**
  298. * GetPrefix
  299. *
  300. * Gets the directory prefix to use for files in this archive
  301. *
  302. * @access public
  303. * @return string prefix
  304. */
  305. public function GetPrefix()
  306. {
  307. if (!empty($this->prefix)) {
  308. return $this->prefix;
  309. }
  310. $pfx = $this->GetProject()->GetSlug() . '/';
  311. if (!empty($this->path))
  312. $pfx .= $this->path . '/';
  313. return $pfx;
  314. }
  315. /**
  316. * SetPrefix
  317. *
  318. * Sets the directory prefix to use for files in this archive
  319. *
  320. * @access public
  321. * @param string $prefix prefix to use
  322. */
  323. public function SetPrefix($prefix = '')
  324. {
  325. if (empty($prefix)) {
  326. $this->prefix = $prefix;
  327. return;
  328. }
  329. if (substr($prefix, -1) != '/') {
  330. $prefix .= '/';
  331. }
  332. $this->prefix = $prefix;
  333. }
  334. /**
  335. * Open
  336. *
  337. * Opens a descriptor for reading archive data
  338. *
  339. * @access public
  340. * @return boolean true on success
  341. */
  342. public function Open()
  343. {
  344. if (!$this->objectHash)
  345. {
  346. throw new Exception('Invalid object for archive');
  347. }
  348. if ($this->handle) {
  349. return true;
  350. }
  351. $args = array();
  352. switch ($this->format) {
  353. case GITPHP_COMPRESS_ZIP:
  354. $args[] = '--format=zip';
  355. break;
  356. case GITPHP_COMPRESS_TAR:
  357. case GITPHP_COMPRESS_BZ2:
  358. case GITPHP_COMPRESS_GZ:
  359. $args[] = '--format=tar';
  360. break;
  361. }
  362. $args[] = '--prefix=' . $this->GetPrefix();
  363. $args[] = $this->objectHash;
  364. $this->handle = GitPHP_GitExe::GetInstance()->Open($this->GetProject()->GetPath(), GIT_ARCHIVE, $args);
  365. if ($this->format == GITPHP_COMPRESS_GZ) {
  366. // hack to get around the fact that gzip files
  367. // can't be compressed on the fly and the php zlib stream
  368. // doesn't seem to daisy chain with any non-file streams
  369. $this->tempfile = tempnam(sys_get_temp_dir(), "GitPHP");
  370. $compress = GitPHP_Config::GetInstance()->GetValue('compresslevel');
  371. $mode = 'wb';
  372. if (is_int($compress) && ($compress >= 1) && ($compress <= 9))
  373. $mode .= $compress;
  374. $temphandle = gzopen($this->tempfile, $mode);
  375. if ($temphandle) {
  376. while (!feof($this->handle)) {
  377. gzwrite($temphandle, fread($this->handle, 1048576));
  378. }
  379. gzclose($temphandle);
  380. $temphandle = fopen($this->tempfile, 'rb');
  381. }
  382. if ($this->handle) {
  383. pclose($this->handle);
  384. }
  385. $this->handle = $temphandle;
  386. }
  387. return ($this->handle !== false);
  388. }
  389. /**
  390. * Close
  391. *
  392. * Close the archive data descriptor
  393. *
  394. * @access public
  395. * @return boolean true on success
  396. */
  397. public function Close()
  398. {
  399. if (!$this->handle) {
  400. return true;
  401. }
  402. if ($this->format == GITPHP_COMPRESS_GZ) {
  403. fclose($this->handle);
  404. if (!empty($this->tempfile)) {
  405. unlink($this->tempfile);
  406. $this->tempfile = '';
  407. }
  408. } else {
  409. pclose($this->handle);
  410. }
  411. $this->handle = null;
  412. return true;
  413. }
  414. /**
  415. * Read
  416. *
  417. * Read a chunk of the archive data
  418. *
  419. * @access public
  420. * @param int $size size of data to read
  421. * @return string archive data
  422. */
  423. public function Read($size = 1048576)
  424. {
  425. if (!$this->handle) {
  426. return false;
  427. }
  428. if (feof($this->handle)) {
  429. return false;
  430. }
  431. $data = fread($this->handle, $size);
  432. if ($this->format == GITPHP_COMPRESS_BZ2) {
  433. $data = bzcompress($data, GitPHP_Config::GetInstance()->GetValue('compresslevel', 4));
  434. }
  435. return $data;
  436. }
  437. /**
  438. * FormatToExtension
  439. *
  440. * Gets the extension to use for a particular format
  441. *
  442. * @access public
  443. * @static
  444. * @param string $format format to get extension for
  445. * @return string file extension
  446. */
  447. public static function FormatToExtension($format)
  448. {
  449. switch ($format) {
  450. case GITPHP_COMPRESS_TAR:
  451. return 'tar';
  452. break;
  453. case GITPHP_COMPRESS_BZ2:
  454. return 'tar.bz2';
  455. break;
  456. case GITPHP_COMPRESS_GZ:
  457. return 'tar.gz';
  458. break;
  459. case GITPHP_COMPRESS_ZIP:
  460. return 'zip';
  461. break;
  462. }
  463. }
  464. /**
  465. * SupportedFormats
  466. *
  467. * Gets the supported formats for the archiver
  468. *
  469. * @access public
  470. * @static
  471. * @return array array of formats mapped to extensions
  472. */
  473. public static function SupportedFormats()
  474. {
  475. $formats = array();
  476. $formats[GITPHP_COMPRESS_TAR] = GitPHP_Archive::FormatToExtension(GITPHP_COMPRESS_TAR);
  477. // TODO check for git > 1.4.3 for zip
  478. $formats[GITPHP_COMPRESS_ZIP] = GitPHP_Archive::FormatToExtension(GITPHP_COMPRESS_ZIP);
  479. if (function_exists('bzcompress'))
  480. $formats[GITPHP_COMPRESS_BZ2] = GitPHP_Archive::FormatToExtension(GITPHP_COMPRESS_BZ2);
  481. if (function_exists('gzencode'))
  482. $formats[GITPHP_COMPRESS_GZ] = GitPHP_Archive::FormatToExtension(GITPHP_COMPRESS_GZ);
  483. return $formats;
  484. }
  485. }