1 package org.apache.maven.plugin.cxx;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.DataOutputStream;
26 import java.io.File;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.io.UnsupportedEncodingException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Properties;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41
42 import org.apache.commons.exec.CommandLine;
43 import org.apache.commons.exec.DefaultExecutor;
44 import org.apache.commons.exec.ExecuteException;
45 import org.apache.commons.exec.Executor;
46 import org.codehaus.plexus.util.StringUtils;
47
48 import org.apache.maven.plugin.MojoExecutionException;
49
50
51 import org.apache.maven.model.FileSet;
52
53 import org.apache.maven.plugins.annotations.LifecyclePhase;
54 import org.apache.maven.plugins.annotations.Mojo;
55 import org.apache.maven.plugins.annotations.Parameter;
56
57 import org.apache.maven.plugin.cxx.utils.ExecutorService;
58 import org.apache.maven.plugin.cxx.utils.FileSetManager;
59
60
61
62
63
64
65 @Mojo( name = "veraxx", defaultPhase = LifecyclePhase.TEST )
66 public class VeraxxMojo extends AbstractLaunchMojo
67 {
68 @Override
69 protected List<String> getArgsList()
70 {
71 return null;
72 }
73
74 private int veraxxVersion = 0;
75
76 @Override
77 protected void preExecute( Executor exec, CommandLine commandLine, Properties enviro ) throws MojoExecutionException
78 {
79 OutputStream outStream = new ByteArrayOutputStream();
80 OutputStream errStream = new ByteArrayOutputStream();
81
82 CommandLine commandLineCheck = new CommandLine( getExecutable() );
83 Executor execCheck = new DefaultExecutor();
84 String[] args = parseCommandlineArgs( "--version" );
85 commandLineCheck.addArguments( args, false );
86 execCheck.setWorkingDirectory( exec.getWorkingDirectory() );
87
88 getLog().info( "Executing command line: " + commandLineCheck );
89
90 int res = 0;
91 try
92 {
93 res = ExecutorService.executeCommandLine( execCheck, commandLineCheck, enviro,
94 outStream, errStream, getInputStream() );
95 }
96 catch ( ExecuteException e )
97 {
98 getLog().info( "Exec Exception while detecting Vera++ version."
99 + " Assume old Vera++ v1.1.x (and less) output parsing style" );
100 getLog().info( "Vera++ err output is : " + errStream.toString() ) ;
101 veraxxVersion = 0;
102
103 return;
104 }
105 catch ( IOException e )
106 {
107 getLog().info( "Vera++ detected version is : " + outStream.toString() ) ;
108 getLog().info( "Vera++ err output is : " + errStream.toString() ) ;
109
110
111
112 getLog().info( "jvm " + System.getProperty( "java.version" )
113 + " (8u11 - 9) workaround, ignoring a " + e.toString() + " during vera++ test command line." );
114
115 }
116
117 if ( isResultCodeAFailure( res ) )
118 {
119 getLog().info( "Vera++ returned a failure result code : " + res );
120
121
122 }
123 DefaultArtifactVersion newFormatMinVersion = new DefaultArtifactVersion( "1.2.0" );
124 DefaultArtifactVersion currentVeraVersion = new DefaultArtifactVersion( outStream.toString() );
125
126 getLog().debug( "Vera++ detected version is : " + outStream.toString() ) ;
127 getLog().debug( "Vera++ version as ArtefactVersion is : " + currentVeraVersion.toString() );
128
129 if ( currentVeraVersion.compareTo( newFormatMinVersion ) < 0 )
130 {
131 getLog().info( "Use old Vera++ v1.1.x (and less) output parsing style" );
132 veraxxVersion = 0;
133 }
134 else
135 {
136 getLog().info( "Use Vera++ v1.2.0 (and more) output parsing style" );
137 veraxxVersion = 1;
138 }
139 }
140
141
142
143
144
145 @Parameter( property = "veraxx.args", defaultValue = "-nodup -showrules" )
146 private String commandArgs;
147
148 @Override
149 protected String getCommandArgs()
150 {
151 String params = "- " + commandArgs + " ";
152 return params;
153 }
154
155
156
157
158
159
160 @Parameter( property = "veraxx.reportsfilePath", defaultValue = "${project.build.directory}/vera++-reports" )
161 private File reportsfileDir;
162
163
164
165
166
167
168 @Parameter( property = "veraxx.reportIdentifier", defaultValue = "" )
169 private String reportIdentifier;
170
171 private String getReportFileName()
172 {
173 return "vera++-result-" + reportIdentifier + ".xml";
174 }
175
176 @Override
177 protected OutputStream getOutputStreamErr()
178 {
179 String outputReportName = new String();
180 if ( reportsfileDir.isAbsolute() )
181 {
182 outputReportName = reportsfileDir.getAbsolutePath() + File.separator + getReportFileName();
183 }
184 else
185 {
186 outputReportName = basedir.getAbsolutePath() + File.separator + reportsfileDir.getPath()
187 + File.separator + getReportFileName();
188 }
189 getLog().info( "Vera++ report location " + outputReportName );
190
191 OutputStream output = System.err;
192 File file = new File( outputReportName );
193 try
194 {
195 new File( file.getParent() ).mkdirs();
196 file.createNewFile();
197 output = new FileOutputStream( file );
198 }
199 catch ( IOException e )
200 {
201 getLog().error( "Vera++ report redirected to stderr since " + outputReportName + " can't be opened" );
202 return output;
203 }
204
205 final DataOutputStream out = new DataOutputStream( output );
206
207 try
208 {
209 out.writeBytes( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
210 out.writeBytes( "<checkstyle version=\"5.0\">\n" );
211 }
212 catch ( IOException e )
213 {
214 getLog().error( "Vera++ xml report write failure" );
215 }
216
217 OutputStream outErrFilter = new OutputStream()
218 {
219 StringBuffer sb = new StringBuffer();
220 public void write( int b ) throws IOException
221 {
222 if ( ( b == '\n' ) || ( b == '\r' ) )
223 {
224 transformCurrentLine();
225
226 sb.delete( 0, sb.length() );
227 }
228 else
229 {
230 sb.append( (char) b );
231 }
232 }
233
234 public void flush() throws IOException
235 {
236 transformCurrentLine();
237 getLog().debug( "Vera++ xml flush() called" );
238 if ( !StringUtils.isEmpty( lastfile ) )
239 {
240 out.writeBytes( "\t</file>\n" );
241 }
242 out.writeBytes( "</checkstyle>\n" );
243 out.flush();
244 }
245
246 String lastfile;
247 private void transformCurrentLine()
248 {
249 if ( sb.length() > 0 )
250 {
251
252
253
254 String p = "^(.+) \\((.+)\\) (.+)$";
255 Pattern pattern = Pattern.compile( p );
256 Matcher matcher = pattern.matcher( sb );
257 getLog().debug( "match " + sb + " on " + p );
258
259 boolean bWinPath = false;
260 if ( sb.charAt( 1 ) == ':' )
261 {
262 bWinPath = true;
263 sb.setCharAt( 1, '_' );
264 }
265
266 if ( matcher.matches() )
267 {
268 String sLine = matcher.group( 1 ) + matcher.group( 2 ) + ":" + matcher.group( 3 );
269 getLog().debug( "rebuild line = " + sLine );
270
271
272 pattern = Pattern.compile( ":" );
273 String[] items = pattern.split( sLine );
274
275 String file, line, rule, comment, severity;
276 file = items.length > 0 ? items[0] : "";
277 line = items.length > 1 ? items[1] : "";
278 rule = items.length > 2 ? items[2] : "";
279 comment = items.length > 3 ? items[3] : "";
280 severity = "warning";
281
282 if ( bWinPath )
283 {
284 StringBuilder s = new StringBuilder( file );
285 s.setCharAt( 1, ':' );
286 file = s.toString();
287 }
288
289
290 try
291 {
292
293 if ( !file.equals( lastfile ) )
294 {
295 if ( !StringUtils.isEmpty( lastfile ) )
296 {
297 out.writeBytes( "\t</file>\n" );
298 }
299 out.writeBytes( "\t<file name=\"" + file + "\">\n" );
300 lastfile = file;
301 }
302 out.writeBytes( "\t\t<error line=\"" + line + "\" severity=\"" + severity
303 + "\" message=\"" + comment + "\" source=\"" + rule + "\"/>\n" );
304 }
305 catch ( IOException e )
306 {
307 getLog().error( "Vera++ xml report write failure" );
308 }
309 }
310 }
311 }
312 };
313 return outErrFilter;
314 }
315
316
317
318
319
320
321 @Parameter( property = "veraxx.excludes", defaultValue = "" )
322 private String excludes;
323
324
325
326
327
328
329 @Parameter()
330 private List sourceDirs = new ArrayList();
331
332 @Override
333 protected InputStream getInputStream()
334 {
335 StringBuilder sourceListString = new StringBuilder();
336 Iterator it = sourceDirs.iterator();
337 while ( it.hasNext() )
338 {
339 FileSet afileSet = new FileSet();
340 String dir = it.next().toString();
341 afileSet.setDirectory( new File( dir ).getAbsolutePath() );
342
343 afileSet.setIncludes( Arrays.asList( new String[]{"**/*.cpp", "**/*.h", "**/*.cxx", "**/*.hxx"} ) );
344 if ( StringUtils.isNotEmpty( excludes ) )
345 {
346 afileSet.setExcludes( Arrays.asList( excludes.split( "," ) ) );
347 }
348 getLog().debug( "vera++ excludes are :" + Arrays.toString( afileSet.getExcludes().toArray() ) );
349
350 FileSetManager aFileSetManager = new FileSetManager();
351 String[] found = aFileSetManager.getIncludedFiles( afileSet );
352
353 for ( int i = 0; i < found.length; i++ )
354 {
355 sourceListString.append( dir + File.separator + found[i] + "\n" );
356 }
357 }
358 InputStream is = System.in;
359 try
360 {
361 getLog().debug( "vera++ sources are :" + sourceListString );
362 is = new ByteArrayInputStream( sourceListString.toString().getBytes( "UTF-8" ) );
363 }
364 catch ( UnsupportedEncodingException e )
365 {
366 getLog().error( "vera++ source list from stdin failure" );
367 }
368 return is;
369 }
370
371 @Override
372 protected String getExecutable()
373 {
374 return "vera++";
375 }
376
377
378
379
380
381
382 @Parameter()
383 private Map environmentVariables = new HashMap();
384
385 @Override
386 protected Map getMoreEnvironmentVariables()
387 {
388 return environmentVariables;
389 }
390
391 @Override
392 protected List<String> getSuccesCode()
393 {
394 return null;
395 }
396
397
398
399
400
401
402 @Parameter( property = "veraxx.workingdir" )
403 private File workingDir;
404
405 @Override
406 protected File getWorkingDir()
407 {
408 if ( null == workingDir )
409 {
410 workingDir = new File( basedir.getPath() );
411 }
412 return workingDir;
413 }
414
415
416
417
418
419
420
421 @Parameter( property = "skipTests", defaultValue = "false" )
422 protected boolean skipTests;
423
424
425
426
427
428
429
430
431 @Parameter( property = "maven.test.skip", defaultValue = "false" )
432 protected boolean skip;
433
434 @Override
435 protected boolean isSkip()
436 {
437 return skipTests || skip;
438 }
439 }