1+ <?php
2+
3+ class PHPCS_Diff_SVN_parser {
4+
5+ // SVN credentials used for checking out individual revisions.
6+ private $ svn_username = '' ; // @todo: add your SVN username here
7+ private $ svn_password = '' ; // @todo: add your SVN password here
8+
9+ // Used to store details about the repo the class was initialized with.
10+ public $ repo ; // Specific repository - eg.: plugin's name.
11+ public $ repo_url ; // SVN repository URL.
12+ public $ table ; // Table used for storing information about revisions.
13+
14+ function __construct ( $ repo ) {
15+
16+ switch ( $ repo ) {
17+
18+ case 'hello-dolly ' :
19+ $ this ->repo_url = 'https://plugins.svn.wordpress.org/ ' ;
20+ break ;
21+
22+ # Add new repos here. See details at the top of this file.
23+ }
24+
25+ $ this ->repo = $ repo ;
26+ }
27+
28+ public function get_diff ( $ folder , $ end_revision , $ start_revision = null , $ options = array () ) {
29+ $ summarize = false ;
30+ $ xml = false ;
31+ $ ignore_space_change = false ;
32+
33+ if ( isset ( $ options ['summarize ' ] ) ) {
34+ $ summarize = (bool ) $ options ['summarize ' ];
35+
36+ // xml is only available in summaries
37+ if ( $ summarize && isset ( $ options ['xml ' ] ) ) {
38+ $ xml = (bool ) $ options ['xml ' ];
39+ }
40+ }
41+
42+ if ( isset ( $ options ['ignore-space-change ' ] ) ) {
43+ $ ignore_space_change = (bool ) $ options ['ignore-space-change ' ];
44+ }
45+
46+ $ end_revision = (int ) $ end_revision ;
47+ $ folder = str_replace ( '.. ' , '' , $ folder ); // Prevent moving up a directory
48+
49+ if ( $ start_revision && is_numeric ( $ start_revision ) ) {
50+ $ start_revision = (int ) $ start_revision ;
51+ } else {
52+ // @todo is this really the best way to get the diff if there was no previous revision?
53+ $ start_revision = 1 ;
54+ }
55+
56+ $ repo_url = esc_url_raw ( trailingslashit ( $ this ->repo_url ) . trailingslashit ( $ this ->repo ) . $ folder );
57+
58+ $ diff = shell_exec (
59+ sprintf ( 'svn diff %s --non-interactive --no-auth-cache --username %s --password %s -r %d:%d %s %s %s ' ,
60+ escapeshellarg ( $ repo_url ),
61+ escapeshellarg ( $ this ->svn_username ),
62+ escapeshellarg ( $ this ->svn_password ),
63+ (int ) $ start_revision ,
64+ (int ) $ end_revision ,
65+ ( $ summarize ? '--summarize ' : '' ),
66+ ( $ xml ? '--xml ' : '' ),
67+ ( $ ignore_space_change ? '-x -b ' : '' )
68+ )
69+ );
70+
71+ return $ diff ;
72+ }
73+
74+ /**
75+ * Collect information about the diff
76+ *
77+ * @param string $diff_file full svn .diff file to be parsed for information
78+ *
79+ * @return array information about the diff
80+ */
81+ public static function parse_diff_for_info ( $ diff_file ){
82+
83+ $ files = preg_split ( '/^Index: (.+)$/m ' , $ diff_file , NULL , PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
84+
85+ //result is a flat array with alternating 'filename', 'file_contents', 'filename', 'file_cotnents'... let's organize that into an associative array 'file_name'=>'file_contents'
86+ $ diff_files = call_user_func_array ( 'array_merge ' , array_map ( function ( $ pair ) { return array ( $ pair [0 ] => $ pair [1 ] ); }, array_chunk ( $ files , 2 ) ) );
87+ $ results = array ();
88+ $ lines_added = $ lines_removed = 0 ;
89+
90+ foreach ( $ diff_files as $ file_name => $ file_diff ) {
91+
92+ //Remove property changes from the file_diff and store it in file_parts[1] if present
93+ $ file_parts = preg_split ( '/Property changes on: (?:.+)/ ' , $ file_diff , NULL , PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
94+ $ file_diff = $ file_parts [0 ];
95+ unset( $ file_parts );
96+
97+ $ results [$ file_name ] = array ( 'file_name ' => $ file_name , 'lines_added ' => 0 , 'lines_removed ' => 0 );
98+
99+ $ results [$ file_name ]['lines ' ] = array ();
100+
101+ $ diff_lines = explode ( PHP_EOL , $ file_diff );
102+ $ old_start = $ new_start = 0 ;
103+ foreach ( $ diff_lines as $ line ) {
104+ switch ( true ) {
105+ case preg_match ( '/^No differences encountered/ ' , $ line ):
106+ case preg_match ( '/^$/ ' , $ line ):
107+ break ;
108+ case preg_match ( '/^(\-\-\-|\+\+\+)/ ' , $ line ):
109+ if ( "--- {$ file_name } (revision 0) " === trim ( str_replace ( "\t" , ' ' , $ line ) ) ) {
110+ $ results [$ file_name ]['is_new_file ' ] = true ;
111+ }
112+ break ;
113+ case preg_match ( '/^@@ [-+]([0-9]+)*,([0-9]+)* [+-]([0-9]+)*,([0-9]+)* @@/ ' , $ line , $ match ):
114+ $ old_start = $ match [1 ];
115+ $ new_start = $ match [3 ];
116+ break ;
117+ case preg_match ( '/^ (.*)/ ' , $ line , $ match ):
118+ $ results [$ file_name ]['lines ' ][] = array (
119+ 'old_line_number ' => $ old_start ,
120+ 'new_line_number ' => $ new_start ,
121+ 'is_context ' => true ,
122+ // 'line' => $match[1], // Might be useful for debug.
123+ );
124+ $ old_start ++; $ new_start ++;
125+ break ;
126+ case preg_match ( '/^\+(.*)/ ' , $ line , $ match ):
127+ $ lines_added ++;
128+ $ results [$ file_name ]['lines_added ' ]++;
129+ $ results [$ file_name ]['lines ' ][] = array (
130+ 'new_line_number ' => $ new_start ,
131+ 'is_added ' => true ,
132+ // 'line' => $match[1], // Might be useful for debug.
133+ );
134+ $ new_start ++;
135+ break ;
136+ case preg_match ( '/^\-(.*)/ ' , $ line , $ match ):
137+ $ lines_removed ++;
138+ $ results [$ file_name ]['lines_removed ' ]++;
139+ $ results [$ file_name ]['lines ' ][] = array (
140+ 'old_line_number ' => $ old_start ,
141+ 'is_removed ' => true ,
142+ // 'line' => $match[1], // Might be useful for debug.
143+ );
144+ $ old_start ++;
145+ break ;
146+ case preg_match ( '/^diff -r/ ' , $ line ):
147+ break ;
148+ }
149+ }
150+
151+ }
152+ $ diff_info = array (
153+ 'file_diffs ' => $ results ,
154+ );
155+
156+ return $ diff_info ;
157+
158+ }
159+
160+ }
0 commit comments