View Javadoc
1   package org.apache.maven.plugin.cxx;
2   
3   /*
4    * Copyright (C) 2011-2016, Neticoa SAS France - Tous droits réservés.
5    * Author(s) : Franck Bonin, Neticoa SAS France
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   *
19   */
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.OutputStream;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.HashSet;
32  
33  import org.codehaus.plexus.util.StringUtils;
34  
35  /* Use enhanced FileSet and FileManager (not the one provided in this project)*/
36  import org.apache.maven.shared.model.fileset.FileSet;
37  import org.apache.maven.shared.model.fileset.util.FileSetManager;
38  
39  import org.apache.maven.plugins.annotations.LifecyclePhase;
40  import org.apache.maven.plugins.annotations.Mojo;
41  import org.apache.maven.plugins.annotations.Parameter;
42  
43  /**
44   * Goal which cppcheck sources.
45   *
46   * @author Franck Bonin 
47   */
48  @Mojo( name = "cppcheck", defaultPhase = LifecyclePhase.TEST )
49  public class CppCheckMojo extends AbstractLaunchMojo
50  {
51      @Override
52      protected List<String> getArgsList()
53      {
54          return null;
55      }
56      
57      /**
58       * Directory where cppcheck should search for source files
59       * 
60       * @since 0.0.4
61       */
62      @Parameter()
63      private List sourceDirs = new ArrayList();
64      
65      /**
66       * Directory where included file shall be found
67       * 
68       * @since 0.0.4
69       */
70      @Parameter( )
71      private List includeDirs = new ArrayList();
72      
73      /**
74       *  Excludes files/folder from analysis (comma separated list of filter)
75       *
76       *  @since 0.0.5
77       */
78      @Parameter( property = "cppcheck.excludes", defaultValue = "" )
79      private String excludes;
80      
81     /**
82       * The Report OutputFile Location.
83       * 
84       * @since 0.0.4
85       */
86      @Parameter( property = "cppcheck.reportsfilePath", defaultValue = "${project.build.directory}/cppcheck-reports" )
87      private File reportsfileDir;
88      
89      /**
90       * The Report OutputFile name identifier.
91       * 
92       * @since 0.0.4
93       */
94      @Parameter( property = "cppcheck.reportIdentifier", defaultValue = "" )
95      private String reportIdentifier;
96      
97      private String getReportFileName()
98      {
99          return "cppcheck-result-" + reportIdentifier + ".xml";
100     }
101     
102     /**
103      * Arguments for the cppcheck program. Shall be -v --enable=style --force --xml 
104      * 
105      */
106     @Parameter( property = "cppcheck.args", defaultValue = "-v --enable=style --force --xml" )
107     private String commandArgs;
108 
109     @Override
110     protected String getCommandArgs()
111     {
112         String params = commandArgs + " ";
113         HashSet<String> excudedSet = new HashSet<String>();
114         
115         Iterator it = includeDirs.iterator();
116         while ( it.hasNext() )
117         {
118             FileSet afileSet = new FileSet();
119             
120             String dir = it.next().toString();
121             params += "-I\"" + dir + "\" ";
122             
123             if ( StringUtils.isNotEmpty( excludes ) )
124             {
125                 afileSet.setDirectory( new File( dir ).getAbsolutePath() );
126                 // $FB pour éviter d'avoir TROP de fichier excludes (inutiles) dans la boucle for ci-après
127                 afileSet.setUseDefaultExcludes( false ); 
128                 afileSet.setExcludes( Arrays.asList( excludes.split( "," ) ) );
129                 getLog().debug( "cppcheck excludes are :" + Arrays.toString( afileSet.getExcludes().toArray() ) );
130                 
131                 FileSetManager aFileSetManager = new FileSetManager();
132                 String[] found = aFileSetManager.getExcludedFiles( afileSet );
133                 excudedSet.addAll( new HashSet<String>( Arrays.asList( found ) ) );
134             }
135         }
136         it = sourceDirs.iterator();
137         while ( it.hasNext() )
138         {
139             FileSet afileSet = new FileSet();
140             
141             String dir = it.next().toString();
142             params += "-I\"" + dir + "\" ";
143             
144             if ( StringUtils.isNotEmpty( excludes ) )
145             {
146                 afileSet.setDirectory( new File( dir ).getAbsolutePath() );
147                 // $FB pour éviter d'avoir TROP de fichiers exclude (inutile) dans la boucle for ci-après
148                 afileSet.setUseDefaultExcludes( false ); 
149                 afileSet.setExcludes( Arrays.asList( excludes.split( "," ) ) );
150                 getLog().debug( "cppcheck excludes are :" + Arrays.toString( afileSet.getExcludes().toArray() ) );
151                 
152                 FileSetManager aFileSetManager = new FileSetManager();
153                 String[] found = aFileSetManager.getExcludedFiles( afileSet );
154                 excudedSet.addAll( new HashSet<String>( Arrays.asList( found ) ) );
155             }
156         }
157         for ( Iterator<String> iter = excudedSet.iterator(); iter.hasNext(); )
158         {
159             String s = iter.next();
160             //cppcheck only check *.cpp, *.cxx, *.cc, *.c++, *.c, *.tpp, and *.txx files
161             // so remove unneeded exclusions
162             if ( s.matches( "(.+\\.cpp)|(.+\\.cxx)|(.+\\.cc)|(.+\\.c\\+\\+)|(.+\\.c)|(.+\\.tpp)|(.+\\.txx)" ) )
163             {
164                 params += "-i\"" + s + "\" ";
165             }
166         }
167         
168         it = sourceDirs.iterator();
169         while ( it.hasNext() )
170         {
171             params += "\"" + it.next() + "\" ";
172         }
173         
174         return params;
175     }
176     
177     @Override
178     protected OutputStream getOutputStreamErr()
179     {
180         String outputReportName = new String();
181         if ( reportsfileDir.isAbsolute() )
182         {
183             outputReportName = reportsfileDir.getAbsolutePath() + File.separator + getReportFileName();
184         }
185         else
186         {
187             outputReportName = basedir.getAbsolutePath() + File.separator + reportsfileDir.getPath()
188             + File.separator + getReportFileName();
189         }
190         
191         getLog().info( "Cppcheck report location " + outputReportName );
192          
193         OutputStream output = System.err;
194         File file = new File( outputReportName );
195         try
196         {
197             new File( file.getParent() ).mkdirs();
198             file.createNewFile();
199             output = new FileOutputStream( file );
200         }
201         catch ( IOException e )
202         {
203             getLog().error( "Cppcheck report redirected to stderr since " + outputReportName + " can't be opened" );
204         }
205 
206         return output;
207     }
208 
209     @Override
210     protected String getExecutable()
211     {
212         return "cppcheck";
213     }
214 
215     /**
216      * Environment variables to pass to cppcheck program.
217      * 
218      * @since 0.0.4
219      */
220     @Parameter()
221     private Map environmentVariables = new HashMap();
222     
223     @Override
224     protected Map getMoreEnvironmentVariables()
225     {
226         return environmentVariables;
227     }
228 
229     @Override
230     protected List<String> getSuccesCode()
231     {
232         return null;
233     }
234 
235     /**
236      * The current working directory. Optional. If not specified, basedir will be used.
237      * 
238      * @since 0.0.4
239      */
240     @Parameter( property = "cppcheck.workingdir" )
241     private File workingDir;
242     
243     @Override
244     protected File getWorkingDir()
245     {
246         if ( null == workingDir )
247         {
248             workingDir = new File( basedir.getPath() );
249         }
250         return workingDir;
251     }
252     
253     /**
254      * Set this to "true" to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite
255      * convenient on occasion.
256      *
257      * @since 0.0.5
258      */
259     @Parameter( property = "skipTests", defaultValue = "false" )
260     protected boolean skipTests;
261     
262     /**
263      * Set this to "true" to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you enable
264      * it using the "maven.test.skip" property, because maven.test.skip shall disables both running the tests
265      * and compiling the tests. Consider using the <code>skipTests</code> parameter instead.
266      *
267      * @since 0.0.5
268      */
269     @Parameter( property = "maven.test.skip", defaultValue = "false" )
270     protected boolean skip;
271     
272     @Override
273     protected boolean isSkip()
274     {
275         return skipTests || skip;
276     }
277 }