1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: namespace Jyxo\Svn;
15:
16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
27: class Result implements \Countable, \SeekableIterator
28: {
29:
30: 31: 32: 33: 34:
35: const OK = 'OK';
36:
37: 38: 39: 40: 41:
42: const KO = 'KO';
43:
44: 45: 46: 47: 48:
49: const ADD = 'A';
50:
51: 52: 53: 54: 55:
56: const DELETE = 'D';
57:
58: 59: 60: 61: 62:
63: const UPDATE = 'U';
64:
65: 66: 67: 68: 69:
70: const CONFLICT = 'C';
71:
72: 73: 74: 75: 76:
77: const MODIFIED = 'M';
78:
79: 80: 81: 82: 83:
84: const MERGE = 'G';
85:
86: 87: 88: 89: 90:
91: const EXTERNALS = 'X';
92:
93: 94: 95: 96: 97:
98: const IGNORED = 'I';
99:
100: 101: 102: 103: 104:
105: const LOCKED = 'L';
106:
107: 108: 109: 110: 111:
112: const NOT_VERSIONED = '?';
113:
114: 115: 116: 117: 118:
119: const MISSING = '!';
120:
121: 122: 123: 124: 125: 126:
127: const DIR_FILE_SWITCH = '~';
128:
129: 130: 131: 132: 133:
134: const SCHEDULED = '+';
135:
136: 137: 138: 139: 140:
141: const SWITCHED = 'S';
142:
143: 144: 145: 146: 147:
148: const NEW_VERSION_EXISTS = '*';
149:
150: 151: 152: 153: 154:
155: protected $statusTable = array(
156: self::ADD => 'A',
157: self::DELETE => 'D',
158: self::UPDATE => 'U',
159: self::CONFLICT => 'C',
160: self::MODIFIED => 'M',
161: self::MERGE => 'G',
162: self::EXTERNALS => 'X',
163: self::IGNORED => 'I',
164: self::LOCKED => 'L',
165: self::NOT_VERSIONED => '?',
166: self::MISSING => '!',
167: self::DIR_FILE_SWITCH => '',
168: self::SCHEDULED => '+',
169: self::SWITCHED => 'S',
170: self::NEW_VERSION_EXISTS => '*',
171: );
172:
173: 174: 175: 176: 177:
178: protected $revision;
179:
180: 181: 182: 183: 184:
185: protected $error = '';
186:
187: 188: 189: 190: 191:
192: protected $status;
193:
194: 195: 196: 197: 198:
199: protected $items = array();
200:
201: 202: 203: 204: 205:
206: protected $pointer = 0;
207:
208: 209: 210: 211: 212: 213: 214:
215: public function __construct($action, $input, $returnCode = 1)
216: {
217: $this->items = $this->parse($action, $input);
218: $this->status = $returnCode === 0 ? self::OK : self::KO;
219: $this->error = $returnCode === 0 ? '' : $input;
220: }
221:
222: 223: 224: 225: 226: 227: 228:
229: protected function parse($action, $input)
230: {
231: switch ($action) {
232: case 'add':
233: case 'status':
234: return $this->parseStatus($input);
235: case 'commit':
236: return $this->parseCommit($input);
237: case 'update':
238: return $this->parseUpdate($input);
239: default:
240:
241: return array();
242: }
243: }
244:
245: 246: 247: 248: 249: 250:
251: protected function parseStatus($input)
252: {
253: $array = explode("\n", (string) $input);
254: foreach ($array as $key => &$line) {
255:
256: $line = trim($line);
257:
258: if (empty($line)) {
259: unset($array[$key]);
260: continue;
261: }
262:
263: $tmp = $line;
264: $line = array();
265:
266: if ($tmp{0} !== ' ') {
267: $line['status'] = $tmp{0};
268: }
269: if ($tmp{1} !== ' ') {
270: $line['properties'] = $tmp{1};
271: }
272: if ($tmp{2} !== ' ') {
273: $line['lock'] = $tmp{2};
274: }
275: if ($tmp{3} !== ' ') {
276: $line['history'] = $tmp{3};
277: }
278: if ($tmp{4} !== ' ') {
279: $line['switch'] = $tmp{4};
280: }
281: $line['file'] = substr($tmp, 7);
282:
283: }
284: return $array;
285: }
286:
287: 288: 289: 290: 291: 292:
293: protected function parseCommit($input)
294: {
295: $array = explode("\n", (string) $input);
296: foreach ($array as $key => &$line) {
297:
298: $line = trim($line);
299:
300: if (empty($line)) {
301: unset($array[$key]);
302: continue;
303: }
304:
305: if (preg_match('/Committed revision ([0-9]+)\./i', $line, $matches)) {
306: $this->revision = (int) $matches[1];
307: unset($array[$key]);
308: continue;
309: }
310:
311: if (!preg_match('/Sending.*/', $line)) {
312: unset($array[$key]);
313: continue;
314: }
315:
316: }
317:
318: return $array;
319: }
320:
321: 322: 323: 324: 325: 326:
327: protected function parseUpdate($input)
328: {
329: $array = explode("\n", (string) $input);
330: foreach ($array as $key => &$line) {
331:
332: $line = trim($line);
333:
334: if (empty($line)) {
335: unset($array[$key]);
336: continue;
337: }
338:
339: if (preg_match('/At revision ([0-9]+)\./i', $line, $matches)) {
340: $this->revision = (int) $matches[1];
341: unset($array[$key]);
342: continue;
343: }
344:
345: }
346:
347: return $array;
348: }
349:
350: 351: 352: 353: 354: 355:
356: public function __get($prop)
357: {
358: return isset($this->$prop) ? $this->$prop : null;
359: }
360:
361: 362: 363: 364: 365: 366: 367:
368: public function seek($position)
369: {
370: $position = (int) $position;
371: if ($position < 0 || $position > count($this->items)) {
372: throw new Exception(sprintf('Illegal index %d', $position));
373: }
374: $this->pointer = $position;
375:
376: return $this;
377: }
378:
379: 380: 381: 382: 383:
384: public function current()
385: {
386: if ($this->valid()) {
387: return $this->items[$this->pointer];
388: }
389:
390: return null;
391: }
392:
393: 394: 395: 396: 397:
398: public function next()
399: {
400: return ++$this->pointer < count($this->items);
401: }
402:
403: 404: 405: 406: 407:
408: public function rewind()
409: {
410: $this->pointer = 0;
411:
412: return $this;
413: }
414:
415: 416: 417: 418: 419:
420: public function key()
421: {
422: return $this->items[$this->pointer];
423: }
424:
425: 426: 427: 428: 429:
430: public function valid()
431: {
432: return $this->pointer < count($this->items);
433: }
434:
435: 436: 437: 438: 439:
440: public function count()
441: {
442: return count($this->items);
443: }
444: }
445: