1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Horde_Vcs_Log_Git extends Horde_Vcs_Log_Base
15: {
16: 17: 18:
19: protected $_parent = null;
20:
21: protected function _init()
22: {
23:
24: $stats = array();
25: list($resource, $stream) = $this->_rep->runCommand('diff-tree --root --numstat ' . escapeshellarg($this->_rev));
26:
27:
28: fgets($stream);
29: while (!feof($stream) && $line = trim(fgets($stream))) {
30: $tmp = explode("\t", $line);
31: $stats[$tmp[2]] = array_slice($tmp, 0, 2);
32: }
33: fclose($stream);
34: proc_close($resource);
35:
36:
37: $cmd = 'whatchanged -m --no-color --pretty=format:"%H%x00%P%x00%an <%ae>%x00%at%x00%d%x00%s%x00%b%n%x00" --no-abbrev -n 1 ' . escapeshellarg($this->_rev);
38: list($resource, $pipe) = $this->_rep->runCommand($cmd);
39:
40: $log = '';
41: while (!feof($pipe) && ($line = fgets($pipe)) && $line != "\0\n") {
42: $log .= $line;
43: }
44:
45: $fields = explode("\0", substr($log, 0, -1));
46: if ($this->_rev != $fields[0]) {
47: throw new Horde_Vcs_Exception(
48: 'Expected ' . $this->_rev . ', got ' . $fields[0]);
49: }
50:
51: $this->_parent = $fields[1];
52: $this->_author = $fields[2];
53: $this->_date = $fields[3];
54: if ($fields[4]) {
55: $value = substr($fields[4], 1, -1);
56: foreach (explode(',', $value) as $val) {
57: $val = trim($val);
58: if (strpos($val, 'refs/tags/') === 0) {
59: $this->_tags[] = substr($val, 10);
60: }
61: }
62: if (!empty($this->_tags)) {
63: sort($this->_tags);
64: }
65: }
66: $this->_log = trim($fields[5] . "\n\n" . $fields[6]);
67:
68:
69:
70:
71:
72: while (!feof($pipe) && $line = fgets($pipe)) {
73: if ($line == "\n") {
74: break;
75: }
76: if (!preg_match('/^:(\d+) (\d+) (\w+) (\w+) (.+)\t(.+)(\t(.+))?/', $line, $matches)) {
77: throw new Horde_Vcs_Exception('Unknown log line format: ' . $line);
78: }
79:
80: $statinfo = isset($stats[$matches[6]])
81: ? array('added' => $stats[$matches[6]][0], 'deleted' => $stats[$matches[6]][1])
82: : array();
83:
84: $this->_files[$matches[6]] = array_merge(array(
85: 'srcMode' => $matches[1],
86: 'dstMode' => $matches[2],
87: 'srcSha1' => $matches[3],
88: 'dstSha1' => $matches[4],
89: 'status' => $matches[5],
90: 'srcPath' => $matches[6],
91: 'dstPath' => isset($matches[7]) ? $matches[7] : ''
92: ), $statinfo);
93: }
94:
95: fclose($pipe);
96: proc_close($resource);
97:
98: $this->_setSymbolicBranches();
99: $this->_branch = $this->_file->getBranch($this->_rev);
100: }
101:
102: 103: 104:
105: public function getHashForPath($path)
106: {
107: $this->_ensureInitialized();
108: return $this->_files[$path]['dstSha1'];
109: }
110:
111: 112: 113:
114: public function getParent()
115: {
116: return $this->_parent;
117: }
118: }