/lib/Gitten/CommitRenderer.php

https://bitbucket.org/kayahr/gitten · PHP · 410 lines · 220 code · 36 blank · 154 comment · 28 complexity · 661171edae1297cf36890a9e9faf7615 MD5 · raw file

  1. <?php
  2. /*
  3. * Copyright (C) 2013 Klaus Reimer <k@ailis.de>
  4. * See LICENSE.md for licensing information.
  5. */
  6. namespace Gitten;
  7. /**
  8. * Renders a commit.
  9. *
  10. * @author Klaus Reimer <k@ailis.de>
  11. */
  12. class CommitRenderer
  13. {
  14. /** The repository. */
  15. private $repo;
  16. /** The current parse mode. */
  17. private $mode;
  18. /** The commit files. */
  19. private $files;
  20. /** The current filename while parsing the patches. */
  21. private $filename;
  22. /** The commit hash. */
  23. private $commitHash;
  24. /** The parent commit hash. */
  25. private $parentHash;
  26. /** If diff parser is currently in header. */
  27. private $inHeader;
  28. /** The current source line while parsing file diff. */
  29. private $srcLine;
  30. /** The current source line while parsing file diff. */
  31. private $destLine;
  32. /** The source lines. */
  33. private $srcLines;
  34. /** The destination lines. */
  35. private $destLines;
  36. /**
  37. * Constructs a new commit renderer.
  38. *
  39. * @param Repo $repo
  40. * The repository.
  41. */
  42. public function __construct(Repo $repo, $commitHash)
  43. {
  44. $this->repo = $repo;
  45. $this->reset();
  46. $this->commitHash = $commitHash;
  47. }
  48. /**
  49. * Returns the repository.
  50. *
  51. * @return Repository
  52. * The repository.
  53. */
  54. public function getRepo()
  55. {
  56. return $this->repo;
  57. }
  58. /**
  59. * Returns the commit hash.
  60. *
  61. * @return string
  62. * The commit hash.
  63. */
  64. public function getCommitHash()
  65. {
  66. return $this->commitHash;
  67. }
  68. /**
  69. * Returns the parent hash.
  70. *
  71. * @return string
  72. * The parent hash.
  73. */
  74. public function getParentHash()
  75. {
  76. return $this->parentHash;
  77. }
  78. /**
  79. * Renders the specified commit.
  80. *
  81. * @param string $hash
  82. * The commit hash.
  83. */
  84. public function finish()
  85. {
  86. // $this->repo->gitForEachLine(array($this, "processLine"), "diff-tree",
  87. // "--numstat", "--raw", "--patch", "--no-renames",
  88. // "--pretty=format:%P", $hash);
  89. if ($this->filename) $this->renderFileFooter();
  90. }
  91. /**
  92. * Resets the renderer.
  93. */
  94. private function reset()
  95. {
  96. $this->mode = 0;
  97. $this->files = array();
  98. $this->commitHash = NULL;
  99. $this->parentHash = NULL;
  100. $this->inHeader = false;
  101. }
  102. /**
  103. * Processes a line of the Git response.
  104. *
  105. * @param string $line
  106. * The Git response line to process.
  107. */
  108. public function processLine($line)
  109. {
  110. switch ($this->mode)
  111. {
  112. case 0:
  113. // We don't care about line endings.
  114. $line = trim($line);
  115. // When line is empty then render the file overview and
  116. // switch over to diff parsing.
  117. if ($line == "")
  118. {
  119. $this->mode = 1;
  120. $this->renderFileList();
  121. break;
  122. }
  123. // Parse the line
  124. if (!$this->parentHash)
  125. $this->parentHash = $line;
  126. else if ($line[0] == ":")
  127. $this->processRawLine($line);
  128. else
  129. $this->processNumStatLine($line);
  130. break;
  131. case 1:
  132. $this->processPatchLine($line);
  133. break;
  134. }
  135. }
  136. /**
  137. * Renders the files in the commit.
  138. */
  139. private function renderFileList()
  140. {
  141. $files = $this->files;
  142. $numFiles = count($files);
  143. $additions = 0;
  144. $deletions = 0;
  145. $maxModifications = 0;
  146. foreach ($files as $file)
  147. {
  148. $additions += $file->getAdditions();
  149. $deletions += $file->getDeletions();
  150. $maxModifications = max($maxModifications,
  151. $file->getModifications());
  152. }
  153. $modifications = $additions + $deletions;
  154. include "parts/commit/files.php";
  155. }
  156. /**
  157. * Creates a commit file for the specified filename. If this file
  158. * was already created before then the already created file is
  159. * returned instead.
  160. *
  161. * @param string $filename
  162. * The filename.
  163. * @return CommitFile
  164. * The file.
  165. */
  166. private function createFile($filename)
  167. {
  168. if (isset($this->files[$filename]))
  169. return $this->files[$filename];
  170. else
  171. {
  172. $file = new CommitFile($this, count($this->files),
  173. $filename);
  174. $this->files[$filename] = $file;
  175. return $file;
  176. }
  177. }
  178. /**
  179. * Processes a line from the raw output.
  180. *
  181. * @param string $line
  182. * The line to process.
  183. */
  184. private function processRawLine($line)
  185. {
  186. $parts = preg_split('/\s+/', substr($line, 1));
  187. $srcMode = $parts[0];
  188. $destMode = $parts[1];
  189. $srcHash = $parts[2];
  190. $destHash = $parts[3];
  191. $type = $parts[4];
  192. $filename = $parts[5];
  193. $file = $this->createFile($filename);
  194. $file->setRawData($type, $srcMode, $destMode, $srcHash, $destHash);
  195. }
  196. /**
  197. * Processes a line from the numstat output.
  198. *
  199. * @param string $line
  200. * The line to process.
  201. */
  202. private function processNumStatLine($line)
  203. {
  204. $parts = preg_split('/\s+/', $line);
  205. $additions = intval($parts[0]);
  206. $deletions = intval($parts[1]);
  207. $binary = ($parts[0] == "-") && ($parts[1] == "-");
  208. $filename = $parts[2];
  209. $file = $this->createFile($filename);
  210. $file->setNumStatData($additions, $deletions, $binary);
  211. }
  212. /**
  213. * Processes a line from the patch output.
  214. *
  215. * @param string $line
  216. * The line to process.
  217. */
  218. private function processPatchLine($line)
  219. {
  220. if (strpos($line, "diff") === 0)
  221. {
  222. $this->processPatchDiffLine($line);
  223. $this->inHeader = true;
  224. $this->sourceLines = array();
  225. $this->destLines = array();
  226. $this->maxSourceLine = 0;
  227. $this->maxDestLine = 0;
  228. }
  229. else if ($line[0] == "@")
  230. {
  231. $this->processPatchChunkLine($line);
  232. $this->inHeader = false;
  233. }
  234. else if (!$this->inHeader)
  235. {
  236. if ($line[0] == " ")
  237. $this->processPatchUnchangedLine($line);
  238. else if ($line[0] == "+")
  239. $this->processPatchAddedLine($line);
  240. else if ($line[0] == "-")
  241. $this->processPatchRemovedLine($line);
  242. }
  243. }
  244. /**
  245. * Processes a diff line from the patch output.
  246. *
  247. * @param string $line
  248. * The line to process.
  249. */
  250. private function processPatchDiffLine($line)
  251. {
  252. $parts = explode(" ", $line);
  253. if ($this->filename)
  254. $this->renderFileFooter();
  255. $this->filename = substr($parts[2], 2);
  256. $this->renderFileHeader();
  257. }
  258. /**
  259. * Processes a chunk line from the patch output.
  260. *
  261. * @param string $line
  262. * The line to process.
  263. */
  264. private function processPatchChunkLine($line)
  265. {
  266. if (!preg_match('/@@ -([0-9,]+) \+([0-9,]+) @@/',
  267. $line, $result))
  268. throw new \RuntimeException("Unable to parse chunk line: $line");
  269. $srcRange = $result[1];
  270. $destRange = $result[2];
  271. $parts = explode(",", $srcRange);
  272. $srcStart = array_shift($parts);
  273. $srcLines = $parts ? array_shift($parts) : 1;
  274. $parts = explode(",", $destRange);
  275. $destStart = array_shift($parts);
  276. $destLines = $parts ? array_shift($parts) : 1;
  277. $this->maxSourceLine = max($this->maxSourceLine, $srcStart +
  278. $srcLines - 1);
  279. $this->maxDestLine = max($this->maxDestLine, $destStart +
  280. $destLines - 1);
  281. $this->sourceLine = $srcStart;
  282. $this->destLine = $destStart;
  283. $this->sourceLines[] = "@@";
  284. $this->destLines[] = "@@";
  285. printf("<span class=\"line chunk\">%s</span>", htmlspecialchars($line));
  286. }
  287. /**
  288. * Processes an unchanged line from the patch output.
  289. *
  290. * @param string $line
  291. * The line to process.
  292. */
  293. private function processPatchUnchangedLine($line)
  294. {
  295. printf("<span class=\"line\">%s</span>", htmlspecialchars($line));
  296. $this->sourceLines[] = $this->sourceLine++;
  297. $this->destLines[] = $this->destLine++;
  298. }
  299. /**
  300. * Processes an added line from the patch output.
  301. *
  302. * @param string $line
  303. * The line to process.
  304. */
  305. private function processPatchAddedLine($line)
  306. {
  307. printf("<span class=\"line add\">%s</span>", htmlspecialchars($line));
  308. $this->sourceLines[] = "";
  309. $this->destLines[] = $this->destLine++;
  310. }
  311. /**
  312. * Processes a deleted line from the patch output.
  313. *
  314. * @param string $line
  315. * The line to process.
  316. */
  317. private function processPatchRemovedLine($line)
  318. {
  319. printf("<span class=\"line delete\">%s</span>", htmlspecialchars($line));
  320. $this->sourceLines[] = $this->sourceLine++;
  321. $this->destLines[] = "";
  322. }
  323. /**
  324. * Renders the file header.
  325. */
  326. private function renderFileHeader()
  327. {
  328. $file = $this->files[$this->filename];
  329. include "parts/commit/fileheader.php";
  330. }
  331. /**
  332. * Renders the file footer.
  333. */
  334. private function renderFileFooter()
  335. {
  336. $file = $this->files[$this->filename];
  337. $sourceLines = $this->sourceLines;
  338. $destLines = $this->destLines;
  339. $maxSourceLine = $this->maxSourceLine;
  340. $maxDestLine = $this->maxDestLine;
  341. $parentBlobUrl = $this->getParentBlobUrl();
  342. $commitBlobUrl = $this->getCommitBlobUrl();
  343. include "parts/commit/filefooter.php";
  344. }
  345. /**
  346. * Returns the URL to the commit blob.
  347. *
  348. * @return string
  349. * The commit blob url or NULL if blob was deleted.
  350. */
  351. public function getCommitBlobUrl()
  352. {
  353. return "Commit blob URL";
  354. /*
  355. $revision = $this->commitHash;
  356. $path = $this->filename;
  357. $repoUrl = $this->repo->getUrl();
  358. return "$repoUrl/blob/$revision/$path";*/
  359. }
  360. /**
  361. * Returns the URL to the parent blob.
  362. *
  363. * @return string
  364. * The parent blob url or NULL if blob was added.
  365. */
  366. public function getParentBlobUrl()
  367. {
  368. return "Parent blob url";
  369. /* $revision = $this->parentHash;
  370. $path = $this->filename;
  371. $repoUrl = $this->repo->getUrl();
  372. return "$repoUrl/blob/$revision/$path";*/
  373. }
  374. }