diff --git a/SourceSVN/SourceSVN.php b/SourceSVN/SourceSVN.php index 669dbd7..132ce3c 100644 --- a/SourceSVN/SourceSVN.php +++ b/SourceSVN/SourceSVN.php @@ -195,14 +195,14 @@ $t_url = $p_repo->url; $t_revision = $p_matches[1]; - $t_svnlog = explode( "\n", shell_exec( "$svn log -v $t_url -r$t_revision" ) ); + $$t_svnlog_xml = shell_exec( "$svn log -v $t_url -r$t_revision --xml" ); if ( SourceChangeset::exists( $p_repo->id, $t_revision ) ) { echo "Revision $t_revision already committed!\n"; return null; } - return $this->process_svn_log( $p_repo, $t_svnlog ); + return $this->process_svn_log_xml( $p_repo, $t_svnlog_xml ); } } @@ -222,12 +222,22 @@ echo "
";
 
+		# finding max revision
+		$t_svninfo_xml = shell_exec( "$svn info $t_url --xml" );
+		$t_max_rev = (integer) (new SimpleXMLElement($t_svninfo_xml))->entry->commit["revision"];
+		
+		if ($t_rev > $t_max_rev)
+		{
+			echo "Next lookup revision ($t_rev) exceeds head revision ($t_max_rev), exiting...";
+			return array();
+		}
+		
 		while( true ) {
 			echo "Requesting svn log for {$p_repo->name} starting with revision {$t_rev}...\n";
 
-			$t_svnlog = explode( "\n", shell_exec( "$svn log -v -r $t_rev:HEAD --limit 200 $t_url" ) );
+			$t_svnlog_xml = shell_exec( "$svn log -v -r $t_rev:HEAD --limit 200 $t_url --xml" );
 
-			$t_changesets = $this->process_svn_log( $p_repo, $t_svnlog );
+			$t_changesets = $this->process_svn_log_xml( $p_repo, $t_svnlog_xml );
 
 			# if an array is returned, processing is done
 			if ( is_array( $t_changesets ) ) {
@@ -336,11 +346,8 @@
 
 		return $s_binary;
 	}
-
-	private function process_svn_log( $p_repo, $p_svnlog ) {
-		$t_state = 0;
-		$t_svnline = str_pad( '', 72, '-' );
-
+	
+	private function process_svn_log_xml( $p_repo, $p_svnlog_xml ) {
 		$t_changesets = array();
 		$t_changeset = null;
 		$t_comments = '';
@@ -351,111 +358,92 @@
 		$t_tag_path = $p_repo->info['tag_path'];
 		$t_ignore_paths = $p_repo->info['ignore_paths'];
 
-		$t_discarded = false;
+		echo "Processing svn log (xml)...\n";
+		# empty log?
+		if (trim($p_svnlog_xml) === "")
+			return array();
 
-		echo "Processing svn log...\n";
+		# parse XML
+		$t_xml = new SimpleXMLElement($p_svnlog_xml);
+		
+		# timezone for conversions in loca
+		$t_utc = new DateTimeZone("UTC");
+		$t_localtz = new DateTimeZone( date_default_timezone_get() );
 
-		foreach( $p_svnlog as $t_line ) {
+		foreach ( $t_xml->logentry as $t_entry)
+		{
+			# time conversion to local time
+			$t_dt = new DateTime($t_entry->date, $t_utc);
+			$t_dt->setTimeZone($t_localtz);
 
-			# starting state, do nothing
-			if ( 0 == $t_state ) {
-				if ( $t_line == $t_svnline ) {
-					$t_state = 1;
+			# create the changeset
+			$t_changeset = new SourceChangeset( $p_repo->id, $t_entry['revision'], '', $t_dt->format('Y-m-d H:i:s'), (string)$t_entry->author, '');
+			
+			# files
+			foreach ($t_entry->paths->path as $t_path)
+			{
+				switch( (string)$t_path["action"] ) {
+					case 'A': $t_action = 'add'; break;
+					case 'D': $t_action = 'rm'; break;
+					case 'M': $t_action = 'mod'; break;
+					case 'R': $t_action = 'mv'; break;
+					default: $t_action = (string)$t_path["action"];
 				}
-
-			# Changeset info
-			} elseif ( 1 == $t_state && preg_match( '/^r([0-9]+) \| ([^|]+) \| ([0-9\-]+) ([0-9:]+)/', $t_line, $t_matches ) ) {
-				if ( !is_null( $t_changeset ) ) {
-					if ( !is_blank( $t_changeset->branch ) ) {
-						$t_changeset->save();
-						$t_changesets[] = $t_changeset;
-					} else {
-						$t_discarded = $t_changeset->revision;
-					}
-				}
-
-				$t_changeset = new SourceChangeset( $p_repo->id, $t_matches[1], '', $t_matches[3] . ' ' . $t_matches[4], $t_matches[2], '' );
-
-				$t_state = 2;
-
-			# Changed paths
-			} elseif ( 2 == $t_state ) {
-				if ( strlen( $t_line ) == 0 ) {
-					$t_state = 3;
-				} else {
-					if ( preg_match( '/^\s+([a-zA-Z])\s+([^\(]+)(?: \(from [^\)]+\))?/', $t_line, $t_matches ) ) {
-						switch( $t_matches[1] ) {
-							case 'A': $t_action = 'add'; break;
-							case 'D': $t_action = 'rm'; break;
-							case 'M': $t_action = 'mod'; break;
-							case 'R': $t_action = 'mv'; break;
-							default: $t_action = $t_matches[1];
-						}
-
-						$t_file = new SourceFile( $t_changeset->id, '', trim( $t_matches[2] ), $t_action );
-						$t_changeset->files[] = $t_file;
-
-						# Branch-checking
-						if ( is_blank( $t_changeset->branch) ) {
-							# Look for standard trunk/branches/tags information
-							if ( $p_repo->info['standard_repo'] ) {
-								if ( preg_match( '@/(?:(trunk)|(?:branches|tags)/([^/]+))@i', $t_file->filename, $t_matches ) ) {
-									if ( !is_blank( $t_matches[1] ) ) {
-										$t_changeset->branch = $t_matches[1];
-									} else {
-										$t_changeset->branch = $t_matches[2];
-									}
-								}
+				
+				$t_file = new SourceFile( $t_changeset->id, '', (string)$t_path, $t_action);
+				$t_changeset->files[] = $t_file;
+				
+				# Branch-checking
+				if ( is_blank( $t_changeset->branch) ) {
+					# Look for standard trunk/branches/tags information
+					if ( $p_repo->info['standard_repo'] ) {
+						if ( preg_match( '@/(?:(trunk)|(?:branches|tags)/([^/]+))@i', $t_file->filename, $t_matches ) ) {
+							if ( !is_blank( $t_matches[1] ) ) {
+								$t_changeset->branch = $t_matches[1];
 							} else {
-								# Look for non-standard trunk path
-								if ( !is_blank( $t_trunk_path ) && preg_match( '@^/*(' . $t_trunk_path . ')@i', $t_file->filename, $t_matches ) ) {
-									$t_changeset->branch = $t_matches[1];
-
-								# Look for non-standard branch path
-								} else if ( !is_blank( $t_branch_path ) && preg_match( '@^/*(?:' . $t_branch_path . ')/([^/]+)@i', $t_file->filename, $t_matches ) ) {
-									$t_changeset->branch = $t_matches[1];
-
-								# Look for non-standard tag path
-								} else if ( !is_blank( $t_tag_path ) && preg_match( '@^/*(?:' . $t_tag_path . ')/([^/]+)@i', $t_file->filename, $t_matches ) ) {
-									$t_changeset->branch = $t_matches[1];
-
-								# Fall back to just using the root folder as the branch name
-								} else if ( !$t_ignore_paths && preg_match( '@/([^/]+)@', $t_file->filename, $t_matches ) ) {
-									$t_changeset->branch = $t_matches[1];
-								}
+								$t_changeset->branch = $t_matches[2];
 							}
 						}
-					}
-				}
-
-			# Changeset comments
-			} elseif ( 3 == $t_state ) {
-				if ( $t_line == $t_svnline ) {
-					$t_state = 1;
-				} else {
-					if ( !is_blank($t_changeset->message) ) {
-						$t_changeset->message .= "\n$t_line";
 					} else {
-						$t_changeset->message .= $t_line;
-					}
-				}
+						# Look for non-standard trunk path
+						if ( !is_blank( $t_trunk_path ) && preg_match( '@^/*(' . $t_trunk_path . ')@i', $t_file->filename, $t_matches ) ) {
+							$t_changeset->branch = $t_matches[1];
 
-			# Should only happen at the end...
-			} else {
-				break;
+						# Look for non-standard branch path
+						} else if ( !is_blank( $t_branch_path ) && preg_match( '@^/*(?:' . $t_branch_path . ')/([^/]+)@i', $t_file->filename, $t_matches ) ) {
+							$t_changeset->branch = $t_matches[1];
+
+						# Look for non-standard tag path
+						} else if ( !is_blank( $t_tag_path ) && preg_match( '@^/*(?:' . $t_tag_path . ')/([^/]+)@i', $t_file->filename, $t_matches ) ) {
+							$t_changeset->branch = $t_matches[1];
+
+						# Fall back to just using the root folder as the branch name
+						} else if ( !$t_ignore_paths && preg_match( '@/([^/]+)@', $t_file->filename, $t_matches ) ) {
+							$t_changeset->branch = $t_matches[1];
+						}
+					}
+				}				
+			}
+			
+			# get the log message
+			$t_changeset->message = (string)$t_entry->msg;
+			
+			
+			// Save changeset and append to array
+			if (!is_null( $t_changeset) ) {
+				if (!is_blank( $t_changeset->branch )) {
+					$t_changeset->save();
+					$t_changesets[] = $t_changeset;
+				}
 			}
 		}
-
+		
 		if ( !is_null( $t_changeset ) ) {
 			echo "Parsed to revision {$t_changeset->revision}.\n";
-
-			$t_changeset->save();
-			$t_changesets[] = $t_changeset;
-
 		} else {
 			echo "No revisions parsed.\n";
 		}
 
-		return $t_changesets;
+		return $t_changesets;	
 	}
 }