1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Horde_Vcs_File_Git extends Horde_Vcs_File_Base
15: {
16: 17: 18: 19: 20:
21: protected $_driver = 'Git';
22:
23: 24: 25: 26: 27:
28: protected $_revlist = array();
29:
30: protected function _init()
31: {
32:
33: if (version_compare($this->_rep->version, '1.6.0', '>=')) {
34: $cmd = 'rev-list --branches -- '
35: . escapeshellarg($this->getSourcerootPath());
36: } else {
37: list($stream, $result) = $this->_rep->runCommand(
38: 'branch -v --no-abbrev');
39: $branch_heads = array();
40: while (!feof($result)) {
41: $line = explode(' ', substr(rtrim(fgets($result)), 2));
42: $branch_heads[] = $line[1];
43: }
44: fclose($result);
45: proc_close($stream);
46:
47: $cmd = 'rev-list ' . implode(' ', $branch_heads) . ' -- '
48: . escapeshellarg($this->getSourcerootPath());
49: }
50:
51: list($stream, $result) = $this->_rep->runCommand($cmd);
52: while (!feof($result)) {
53: $line = trim(fgets($result));
54: if (strlen($line)) {
55: $this->_revs[] = $line;
56: }
57: }
58: fclose($result);
59: proc_close($stream);
60:
61: if (!$this->_revs) {
62: $branch = empty($this->_branch) ? null : $this->_branch;
63: if (!$this->_rep->isFile($this->getSourcerootPath(), $branch)) {
64: throw new Horde_Vcs_Exception('No such file: ' . $this->getSourcerootPath());
65: } else {
66: throw new Horde_Vcs_Exception('No revisions found');
67: }
68: }
69:
70: $branchlist = empty($this->_branch)
71: ? array_keys($this->getBranches())
72: : array($this->_branch);
73:
74:
75: $log_list = null;
76: $cmd = 'rev-list';
77: foreach ($branchlist as $branch) {
78: $cmd .= ' ' . escapeshellarg($branch);
79: }
80: $cmd .= ' -- ' . escapeshellarg($this->getSourcerootPath());
81: list($stream, $result) = $this->_rep->runCommand($cmd);
82:
83: if (!feof($result)) {
84: $revs = explode("\n", trim(stream_get_contents($result)));
85: $log_list = $revs;
86: }
87: fclose($result);
88: proc_close($stream);
89:
90: if (is_null($log_list)) {
91: $log_list = empty($this->_branch) ? $this->_revs : array();
92: }
93: foreach ($log_list as $val) {
94: $this->_logs[$val] = $this->_getLog($val);
95: }
96:
97:
98: $cmd = 'rev-list %s -- ' . escapeshellarg($this->getSourcerootPath());
99: foreach ($branchlist as $branch) {
100: list($stream, $result) = $this->_rep->runCommand(
101: sprintf($cmd, escapeshellarg($branch)));
102: if (!feof($result)) {
103: $revs = explode("\n", trim(stream_get_contents($result)));
104: $this->_revlist[$branch] = $revs;
105: }
106: fclose($result);
107: proc_close($stream);
108: }
109: }
110:
111: 112: 113: 114: 115: 116:
117: public function getRevision()
118: {
119: $this->_ensureInitialized();
120: if (empty($this->_branch)) {
121: return parent::getRevision();
122: }
123:
124: $rev = reset($this->_revlist[$this->_branch]);
125: if (is_null($rev)) {
126: throw new Horde_Vcs_Exception('No revisions');
127: }
128:
129: return $rev;
130: }
131:
132: 133: 134: 135: 136: 137: 138:
139: public function getPreviousRevision($rev)
140: {
141: $this->_ensureInitialized();
142:
143: if (empty($this->_branch)) {
144: return parent::getPreviousRevision($rev);
145: }
146:
147: $key = array_search($rev, $this->_revlist[$this->_branch]);
148: return ($key !== false &&
149: isset($this->_revlist[$this->_branch][$key + 1]))
150: ? $this->_revlist[$this->_branch][$key + 1]
151: : null;
152: }
153:
154: 155: 156: 157: 158: 159: 160:
161: public function getHashForRevision($rev)
162: {
163: $this->_ensureInitialized();
164: if (!isset($this->_logs[$rev])) {
165: throw new Horde_Vcs_Exception('This file doesn\'t exist at that revision');
166: }
167: return $this->_logs[$rev]->getHashForPath($this->getSourcerootPath());
168: }
169:
170: 171: 172:
173: public function getBranchList()
174: {
175: return $this->_revlist;
176: }
177:
178: 179: 180: 181: 182: 183: 184:
185: public function getBranch($rev)
186: {
187: $branches = array();
188:
189: foreach (array_keys($this->_revlist) as $val) {
190: if (array_search($rev, $this->_revlist[$val]) !== false) {
191: $branches[] = $val;
192: }
193: }
194:
195: return $branches;
196: }
197:
198: 199: 200: 201: 202: 203:
204: public function getPath()
205: {
206: return $this->getSourcerootPath();
207: }
208:
209: 210: 211:
212: public function getBranches()
213: {
214: 215: 216:
217: $revlist = $this->_rep->getBranchList();
218: if (!empty($this->_branch) &&
219: !in_array($this->_branch, $revlist)) {
220: $revlist[$this->_branch] = $this->_branch;
221: }
222: return $revlist;
223: }
224:
225: 226: 227:
228: public function getLog($rev = null)
229: {
230: if (is_null($rev)) {
231: $this->_ensureInitialized();
232: return $this->_logs;
233: } else {
234: if (!isset($this->_logs[$rev])) {
235: $this->_logs[$rev] = $this->_getLog($rev);
236: }
237:
238: return isset($this->_logs[$rev]) ? $this->_logs[$rev] : null;
239: }
240: }
241:
242: 243: 244: 245: 246: 247:
248: public function getLastLog()
249: {
250: $branch = empty($this->_branch)
251: ? $this->_rep->getDefaultBranch()
252: : $this->_branch;
253: $cmd = 'rev-list -n 1 ' . escapeshellarg($branch)
254: . ' -- ' . escapeshellarg($this->getSourcerootPath());
255: list($stream, $result) = $this->_rep->runCommand($cmd);
256: $rev = trim(fgets($result));
257: fclose($result);
258: proc_close($stream);
259: return new Horde_Vcs_QuickLog_Git($this->_rep, $rev);
260: }
261:
262: 263: 264:
265: public function revisionCount()
266: {
267: if (empty($this->_branch)) {
268: return parent::revisionCount();
269: }
270: $this->_ensureInitialized();
271: return count($this->_revlist[$this->_branch]);
272: }
273:
274: 275: 276:
277: public function getTags()
278: {
279: list($stream, $result) = $this->_rep->runCommand('show-ref --tags');
280: $tags = array();
281: while (!feof($result)) {
282: $line = trim(fgets($result));
283: if ($line) {
284: list($rev, $tag) = explode(' ', $line);
285: $tags[basename($tag)] = $rev;
286: }
287: }
288: fclose($result);
289: proc_close($stream);
290: return $tags;
291: }
292: }
293: