Skip to content

Commit e02794f

Browse files
bright-toolsdregad
authored andcommitted
Improve error detection & handling when invoking SVN
Move the call to plugin_push_current() to be before the first call to svn_binary() to ensure that svn_binary()'s calls to plugin_config_get() retrieve the options from SourceSVN's config options rather than any plugin inheriting from SourceSVN Fixes mantisbt-plugins#247
1 parent 4dafa28 commit e02794f

File tree

2 files changed

+51
-32
lines changed

2 files changed

+51
-32
lines changed

SourceSVN/SourceSVN.php

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ class SourceSVNPlugin extends MantisSourcePlugin {
1616
* Error constants
1717
*/
1818
const ERROR_PATH_INVALID = 'path_invalid';
19-
const ERROR_RUN_SVN = 'run_svn';
19+
const ERROR_SVN_RUN = 'svn_run';
20+
const ERROR_SVN_CMD = 'svn_cmd';
2021

2122
public function register() {
2223
$this->name = plugin_lang_get( 'title' );
@@ -45,7 +46,8 @@ public function config() {
4546
public function errors() {
4647
$t_errors_list = array(
4748
self::ERROR_PATH_INVALID,
48-
self::ERROR_RUN_SVN,
49+
self::ERROR_SVN_RUN,
50+
self::ERROR_SVN_CMD,
4951
);
5052

5153
foreach( $t_errors_list as $t_error ) {
@@ -250,11 +252,10 @@ public function update_config() {
250252

251253
public function commit( $p_repo, $p_data ) {
252254
if ( preg_match( '/(\d+)/', $p_data, $p_matches ) ) {
253-
$svn = $this->svn_call( $p_repo );
254255

255256
$t_url = $p_repo->url;
256257
$t_revision = $p_matches[1];
257-
$t_svnlog_xml = shell_exec( "$svn log -v $t_url -r$t_revision --xml" );
258+
$t_svnlog_xml = $this->svn_run( "log -v $t_url -r$t_revision --xml", $p_repo );
258259

259260
if ( SourceChangeset::exists( $p_repo->id, $t_revision ) ) {
260261
echo "Revision $t_revision already committed!\n";
@@ -266,8 +267,6 @@ public function commit( $p_repo, $p_data ) {
266267
}
267268

268269
public function import_full( $p_repo ) {
269-
$this->svn_check();
270-
$svn = $this->svn_call( $p_repo );
271270

272271
$t_changeset_table = plugin_table( 'changeset', 'Source' );
273272

@@ -279,18 +278,11 @@ public function import_full( $p_repo ) {
279278
$t_url = $p_repo->url;
280279
$t_rev = ( false === $t_db_revision ? 0 : $t_db_revision + 1 );
281280

282-
283281
# finding max revision
284-
$t_svninfo_xml = shell_exec( "$svn info $t_url --xml" );
285-
try {
286-
# create parser
287-
$t_svninfo_parsed_xml = new SimpleXMLElement($t_svninfo_xml);
288-
}
289-
catch( Exception $e ) {
290-
# parsing error - no success here
291-
echo '<pre>svn info returned invalid xml code</pre>';
292-
return array();
293-
}
282+
$t_svninfo_xml = $this->svn_run( "info $t_url --xml", $p_repo );
283+
# create parser
284+
$t_svninfo_parsed_xml = new SimpleXMLElement($t_svninfo_xml);
285+
294286
$t_max_rev = (integer) $t_svninfo_parsed_xml->entry->commit['revision'];
295287

296288
# this is required because invalid revision number render invalid xml output for svn log
@@ -299,12 +291,11 @@ public function import_full( $p_repo ) {
299291
return array();
300292
}
301293

302-
303294
echo '<pre>';
304295
echo "Requesting svn log for {$p_repo->name} starting with revision {$t_rev}...\n";
305296

306297
# get the svn log in xml format
307-
$t_svnlog_xml = shell_exec( "$svn log -v -r $t_rev:HEAD --limit 200 $t_url --xml" );
298+
$t_svnlog_xml = $this->svn_run( "log -v -r $t_rev:HEAD --limit 200 $t_url --xml", $p_repo );
308299

309300
# parse the changesets
310301
$t_changesets = $this->process_svn_log_xml( $p_repo, $t_svnlog_xml );
@@ -317,12 +308,46 @@ public function import_latest( $p_repo ) {
317308
return $this->import_full( $p_repo );
318309
}
319310

320-
private function svn_check() {
321-
$svn = self::svn_call();
311+
/**
312+
* Execute SVN command, catching & raising errors in both
313+
* execution and output
314+
* @param string $p_cmd Command and any parameters
315+
* @param SourceRepo $p_repo Repository to access
316+
* @return string Output of SVN command
317+
*/
318+
private function svn_run( $p_cmd, $p_repo = null )
319+
{
320+
# Get "base" SVN command, including any configured parameters
321+
$t_svn_exe = self::svn_call( $p_repo );
322+
# Append specific cmd & params
323+
$t_svn_cmd = "$t_svn_exe $p_cmd";
324+
325+
$t_svn_proc = proc_open(
326+
$t_svn_cmd,
327+
array( array( 'pipe', 'r' ), array( 'pipe', 'w' ), array( 'pipe', 'w' ) ),
328+
$t_pipes
329+
);
330+
331+
# Check & report execution failure
332+
if( $t_svn_proc === false ) {
333+
plugin_error( self::ERROR_SVN_RUN );
334+
}
322335

323-
if ( is_blank( shell_exec( "$svn help" ) ) ) {
324-
plugin_error( self::ERROR_RUN_SVN );
336+
# Get output of the process & clean up
337+
$t_stderr = stream_get_contents( $t_pipes[2] );
338+
fclose( $t_pipes[2] );
339+
$t_svn_out = stream_get_contents( $t_pipes[1] );
340+
fclose( $t_pipes[1] );
341+
fclose( $t_pipes[0] );
342+
proc_close( $t_svn_proc );
343+
344+
# Error handling
345+
if( $t_stderr ) {
346+
error_parameters( trim( $t_stderr ) );
347+
plugin_error( self::ERROR_SVN_CMD );
325348
}
349+
350+
return $t_svn_out;
326351
}
327352

328353
private function svn_call( $p_repo=null ) {
@@ -435,13 +460,7 @@ private function process_svn_log_xml( $p_repo, $p_svnlog_xml ) {
435460
return array();
436461

437462
# parse XML
438-
try {
439-
$t_xml = new SimpleXMLElement($p_svnlog_xml);
440-
}
441-
catch( Exception $e ) {
442-
echo 'Parsing error of xml log...';
443-
return array();
444-
}
463+
$t_xml = new SimpleXMLElement($p_svnlog_xml);
445464

446465
# timezone for conversions in loca
447466
$t_utc = new DateTimeZone('UTC');

SourceSVN/lang/strings_english.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ $s_plugin_SourceSVN_svnssl = 'SVN: Trust All SSL Certs<br/><span class="small">(
2424
$s_plugin_SourceSVN_winstart = 'SVN: Use Windows `start`<br/><span class="small">(Requires a configured path to binary)</span>';
2525

2626
$s_plugin_SourceSVN_error_path_invalid = 'Path to Subversion binary is invalid, inaccessible or not a directory.';
27-
$s_plugin_SourceSVN_error_run_svn = 'shell_exec() failed to execute Subversion.';
28-
27+
$s_plugin_SourceSVN_error_svn_run = 'Failed to execute Subversion.';
28+
$s_plugin_SourceSVN_error_svn_cmd = 'Subversion execution returned an error: "%1$s".';

0 commit comments

Comments
 (0)