1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: /**
15: * SVN client for PHP.
16: *
17: * Does not use the php_svn extension, but executes SVN binaries directly.
18: *
19: * @category Jyxo
20: * @package Jyxo_Svn
21: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
22: * @license https://github.com/jyxo/php/blob/master/license.txt
23: * @author Matěj Humpál
24: * @author Ondřej Nešpor
25: */
26: class Jyxo_Svn_Client
27: {
28:
29: /**
30: * SVN username.
31: *
32: * @var string
33: */
34: protected $user = '';
35:
36: /**
37: * SVN user password.
38: *
39: * @var string
40: */
41: protected $password = '';
42:
43: /**
44: * Additional SVN parameters.
45: *
46: * @var array
47: */
48: protected $additional = array();
49:
50: /**
51: * Path to the SVN binary.
52: *
53: * @var string
54: */
55: protected $svnBinary = '/usr/bin/svn';
56:
57: /**
58: * Constructor.
59: *
60: * @param string $user SVN username
61: * @param string $password SVN user password
62: * @param array $additional Additional parameters
63: * @param string $svnBinary SVN binary path
64: */
65: public function __construct($user = '', $password = '', array $additional = array(), $svnBinary = '')
66: {
67: $this->user = (string) $user;
68: $this->password = (string) $password;
69: $this->additional = $additional;
70: $this->svnBinary = (string) $svnBinary;
71: }
72:
73: /**
74: * SVN checkout.
75: *
76: * @param string $url Repository URL
77: * @param string $path Local working copy path
78: * @param mixed $params Additional parameters
79: * @param string $user SVN username
80: * @param string $password SVN user password
81: * @return Jyxo_Svn_Result
82: */
83: public function checkout($url, $path, $params = null, $user = '', $password = '')
84: {
85: return $this->callSvn('checkout', $user, $password, array_merge((array) $url, (array) $params, (array) $path));
86: }
87:
88: /**
89: * SVN checkout.
90: *
91: * @param string $url Repository URL
92: * @param string $path Local working copy path
93: * @param mixed $params Additional parameters
94: * @param string $user SVN username
95: * @param string $password SVN user password
96: * @return Jyxo_Svn_Result
97: */
98: public function co($url, $path, $params = null, $user = '', $password = '')
99: {
100: return $this->checkout($url, $path, $params, $user, $password);
101: }
102:
103: /**
104: * SVN Update.
105: *
106: * @param string $path Local working copy path
107: * @param mixed $params Additional parameters
108: * @param string $user SVN username
109: * @param string $password SVN user password
110: * @return Jyxo_Svn_Result
111: */
112: public function update($path, $params = null, $user = '', $password = '')
113: {
114: return $this->callSvn('update', $user, $password, array_merge((array) $params, (array) $path));
115: }
116:
117: /**
118: * SVN Update.
119: *
120: * @param string $path Local working copy path
121: * @param mixed $params Additional parameters
122: * @param string $user SVN username
123: * @param string $password SVN user password
124: * @return Jyxo_Svn_Result
125: */
126: public function up($path, $params = null, $user = '', $password = '')
127: {
128: return $this->update($path, $params, $user, $password);
129: }
130:
131: /**
132: * SVN commit.
133: *
134: * @param string $path Local working copy path
135: * @param string $message Commit message
136: * @param mixed $params Additional parameters
137: * @param string $user SVN username
138: * @param string $password SVN user password
139: * @return Jyxo_Svn_Result
140: */
141: public function commit($path, $message, $params = null, $user = '', $password = '')
142: {
143: return $this->callSvn('commit', $user, $password, array_merge((array) $params, array('-m' => $message), (array) $path));
144: }
145:
146: /**
147: * SVN commit.
148: *
149: * @param string $path Local working copy path
150: * @param string $message Commit message
151: * @param mixed $params Additional parameters
152: * @param string $user SVN username
153: * @param string $password SVN user password
154: * @return Jyxo_Svn_Result
155: */
156: public function ci($path, $message, $params = null, $user = '', $password = '')
157: {
158: return $this->commit($path, $message, $params, $user, $password);
159: }
160:
161: /**
162: * Runs SVN add on the given path.
163: *
164: * @param array $path Path to be added to SVN
165: * @return Jyxo_Svn_Result
166: */
167: public function add(array $path)
168: {
169: return $this->callSvn('add', false, false, $path);
170: }
171:
172: /**
173: * Runs SVN delete on the given path.
174: *
175: * @param array $path Path to be deleted from SVN
176: * @return Jyxo_Svn_Result
177: */
178: public function delete(array $path)
179: {
180: return $this->callSvn('delete', false, false, $path);
181: }
182:
183: /**
184: * Retrieves SVN status information of the given path.
185: *
186: * @param array $path Checked path
187: * @return Jyxo_Svn_Result
188: */
189: public function status(array $path)
190: {
191: return $this->callSvn('status', false, false, $path);
192: }
193:
194: /**
195: * Executes SVN binary with given parameters.
196: *
197: * @param string $action Action
198: * @param string $user Username
199: * @param string $password User password
200: * @param string $params Additional parameters
201: * @return Jyxo_Svn_Result
202: * @throws Jyxo_Svn_Exception On execute error
203: */
204: protected function callSvn($action, $user, $password, $params)
205: {
206: try {
207:
208: $command = escapeshellcmd($this->svnBinary) . ' ' . escapeshellarg($action);
209:
210: $command .= $this->getUserString($user);
211: $command .= $this->getPasswordString($password);
212:
213: switch ($action) {
214: case 'add':
215: case 'delete':
216: $command .= $this->getAdditionalParams($params, true);
217: break;
218: default:
219: $command .= $this->getAdditionalParams($params, false);
220: break;
221: }
222:
223: try {
224:
225: $shell = new Jyxo_Shell_Client();
226: $shell->exec($command, $status);
227:
228: return new Jyxo_Svn_Result($action, $shell->getOut(), $status);
229:
230: } catch (Jyxo_Shell_Exception $e) {
231: throw $e;
232: }
233:
234: } catch (Exception $e) {
235: throw new Jyxo_Svn_Exception(sprintf('SVN %s failed: %s', $action, $e->getMessage()), 0, $e);
236: }
237: }
238:
239:
240: /**
241: * Sets SVN username.
242: *
243: * @param string $user Username
244: * @return Jyxo_Svn_Client
245: */
246: public function setUser($user)
247: {
248: $this->user = (string) $user;
249:
250: return $this;
251: }
252:
253: /**
254: * Sets SVN user password.
255: *
256: * @param string $password Password
257: * @return Jyxo_Svn_Client
258: */
259: public function setPassword($password)
260: {
261: $this->password = (string) $password;
262:
263: return $this;
264: }
265:
266: /**
267: * Sets additional parameters.
268: *
269: * @param array $params Array of parameters
270: * @return Jyxo_Svn_Client
271: */
272: public function setAdditionalParams(array $params)
273: {
274: $this->additional = $params;
275:
276: return $this;
277: }
278:
279: /**
280: * Sets SVN binary path.
281: *
282: * @param string $path Path to the SVN binary
283: * @return Jyxo_Svn_Client
284: */
285: public function setSvnBinary($path)
286: {
287: $this->svnBinary = (string) $path;
288:
289: return $this;
290: }
291:
292: /**
293: * Adds an additional parameter.
294: *
295: * @param string $param Parameter name
296: * @param string $value Parameter value
297: * @return Jyxo_Svn_Client
298: */
299: public function addAdditionalParam($param, $value = '')
300: {
301: if (!empty($value)) {
302: $this->additional[$param] = escapeshellarg($value);
303: } else {
304: $this->additional[] = $param;
305: }
306:
307: return $this;
308: }
309:
310: /**
311: * Returns SVN username with the given value for use as SVN binary parameter.
312: *
313: * Username given in the argument has precedence over the value stored in object's attribute.
314: * Returns empty string if no username is set in any way.
315: *
316: * @param mixed $user Username
317: * @return string
318: */
319: protected function getUserString($user = '')
320: {
321: if (false === $user) {
322: return '';
323: } elseif (!empty($user)) {
324: return ' --username ' . escapeshellarg($user);
325: } elseif (!empty($this->user)) {
326: return ' --username ' . escapeshellarg($this->user);
327: } else {
328: return '';
329: }
330: }
331:
332: /**
333: * Returns SVN user password with the given value for use as SVN binary parameter.
334: *
335: * Password given in the argument has precedence over the value stored in object's attribute.
336: * Returns empty string if no password is set in any way.
337: *
338: * @param mixed $password Password
339: * @return string
340: */
341: protected function getPasswordString($password = '')
342: {
343: if (false === $password) {
344: return '';
345: } elseif (!empty($password)) {
346: return ' --password ' . escapeshellarg($password);
347: } elseif (!empty($this->password)) {
348: return ' --password ' . escapeshellarg($this->password);
349: } else {
350: return '';
351: }
352: }
353:
354: /**
355: * Returns additional parameters with the given value for use as SVN binary parameters.
356: *
357: * Parameters given in the argument have precedence over values stored in object's attribute.
358: * If parameters are given as arrays, they get merged.
359: *
360: * Returns empty string if no parameters are set in any way.
361: *
362: * @param mixed $params Parameters
363: * @param boolean $pathsOnly Use only path-parameters (not beginning with a dash "-")
364: * @return string
365: */
366: protected function getAdditionalParams($params = array(), $pathsOnly = false)
367: {
368: $ret = ' ';
369:
370: foreach ($this->additional as $param => $value) {
371:
372: // If the key exists in $params or it is numeric, skip it.
373: if (isset($params[$param]) && !is_numeric($param)) {
374: continue;
375: }
376:
377: // If we want only paths, skip parameters beginning with a dash "-".
378: if ($pathsOnly && ($param{0} == '-' || $value{0} == '-')) {
379: continue;
380: }
381:
382: // If the key is not numeric, add it as well.
383: if (!is_numeric($param)) {
384: $ret .= ' ' . $param;
385: }
386: // And finally add the parameter value.
387: $ret .= ' ' . $value;
388:
389: }
390:
391: foreach ((array) $params as $param => $value) {
392:
393: // If we want only paths.
394: if ($pathsOnly && ($param{0} == '-' || $value{0} == '-')) {
395: continue;
396: }
397:
398: if (!is_numeric($param)) {
399: $ret .= ' ' . $param;
400: }
401: $ret .= ' ' . escapeshellarg($value);
402:
403: }
404:
405: return $ret;
406: }
407: }
408: