forked from horde/horde
/
Svn.php
219 lines (192 loc) · 6.05 KB
/
Svn.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<?php
/**
* Horde_Vcs_Svn implementation.
*
* Constructor args:
* <pre>
* 'sourceroot': The source root for this repository
* 'paths': Hash with the locations of all necessary binaries: 'svn', 'diff'
* </pre>
*
* Copyright 2000-2014 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Anil Madhavapeddy <anil@recoil.org>
* @author Michael Slusarz <slusarz@horde.org>
* @package Vcs
*/
class Horde_Vcs_Svn extends Horde_Vcs_Base
{
/**
* The current driver.
*
* @var string
*/
protected $_driver = 'Svn';
/**
* Driver features.
*
* @var array
*/
protected $_features = array(
'deleted' => false,
'patchsets' => true,
'branches' => false,
'snapshots' => false);
/**
* SVN username.
*
* @var string
*/
protected $_username = '';
/**
* SVN password.
*
* @var string
*/
protected $_password = '';
/**
* Constructor.
*
* @param array $params Required parameters (see above).
*/
public function __construct($params = array())
{
if (!empty($params['username'])) {
$this->_username = $params['username'];
}
if (!empty($params['password'])) {
$this->_password = $params['password'];
}
parent::__construct($params);
}
/**
* TODO
*/
public function getCommand()
{
$svnPath = $this->getPath('svn');
$tempDir = isset($this->_paths['svn_home'])
? $this->_paths['svn_home']
: sys_get_temp_dir();
$command = $svnPath . ' --non-interactive --config-dir ' . $tempDir;
if ($this->_username) {
$command .= ' --username ' . $this->_username;
}
if ($this->_password) {
$command .= ' --password ' . $this->_password;
}
return $command;
}
/**
* TODO
*/
public function annotate($fileob, $rev)
{
$this->assertValidRevision($rev);
$command = $this->getCommand() . ' annotate -r ' . escapeshellarg('1:' . $rev) . ' ' . escapeshellarg($fileob->getPath()) . ' 2>&1';
$pipe = popen($command, 'r');
if (!$pipe) {
throw new Horde_Vcs_Exception('Failed to execute svn annotate: ' . $command);
}
$lines = array();
$lineno = 1;
while (!feof($pipe)) {
$line = fgets($pipe, 4096);
if (preg_match('/^\s+(\d+)\s+([\w\.]+)\s(.*)$/', $line, $regs)) {
$lines[] = array(
'rev' => $regs[1],
'author' => trim($regs[2]),
'date' => '',
'line' => $regs[3],
'lineno' => $lineno++
);
}
}
pclose($pipe);
return $lines;
}
/**
* Function which returns a file pointing to the head of the requested
* revision of a file.
*
* @param string $fullname Fully qualified pathname of the desired file
* to checkout
* @param string $rev Revision number to check out
*
* @return resource A stream pointer to the head of the checkout.
*/
public function checkout($fullname, $rev)
{
$this->assertValidRevision($rev);
if ($RCS = popen($this->getCommand() . ' cat -r ' . escapeshellarg($rev) . ' ' . escapeshellarg($fullname) . ' 2>&1', VC_WINDOWS ? 'rb' : 'r')) {
return $RCS;
}
throw new Horde_Vcs_Exception('Couldn\'t perform checkout of the requested file');
}
/**
* TODO
*/
public function isValidRevision($rev)
{
return $rev && (string)(int)$rev == $rev;
}
/**
* Create a range of revisions between two revision numbers.
*
* @param Horde_Vcs_File_Svn $file The desired file.
* @param string $r1 The initial revision.
* @param string $r2 The ending revision.
*
* @return array The revision range, or empty if there is no straight
* line path between the revisions.
*/
public function getRevisionRange(Horde_Vcs_File_Base $file, $r1, $r2)
{
// TODO
}
/**
* Obtain the differences between two revisions of a file.
*
* @param Horde_Vcs_File_Svn $file The desired file.
* @param string $rev1 Original revision number to compare
* from.
* @param string $rev2 New revision number to compare against.
* @param array $opts The following optional options:
* - 'num': (integer) DEFAULT: 3
* - 'type': (string) DEFAULT: 'unified'
* - 'ws': (boolean) DEFAULT: true
*
* @return string|boolean False on failure, or a string containing the
* diff on success.
*/
protected function _diff(Horde_Vcs_File_Base $file, $rev1, $rev2, $opts)
{
$diff = array();
$flags = '';
if (!$opts['ws']) {
$flags .= ' -bB ';
}
switch ($opts['type']) {
case 'context':
$flags .= '--context=' . (int)$opts['num'];
break;
case 'unified':
$flags .= '-p --unified=' . (int)$opts['num'];
break;
case 'column':
$flags .= '--side-by-side --width=120';
break;
case 'ed':
$flags .= '-e';
break;
}
// TODO: add options for $hr options - however these may not
// be compatible with some diffs.
$command = $this->getCommand() . " diff --diff-cmd " . $this->getPath('diff') . ' -r ' . escapeshellarg($rev1 . ':' . $rev2) . ' -x ' . escapeshellarg($flags) . ' ' . escapeshellarg($file->getPath()) . ' 2>&1';
exec($command, $diff);
return $diff;
}
}