Permalink
Browse files

Issue #3287: added exclude directory option

  • Loading branch information...
rnveach committed Jun 18, 2016
1 parent 5da6474 commit 90084407fdb6464469e95a9a000e1299fbaf3da7
View
@@ -149,7 +149,7 @@
<!-- Suppressions from PMD configuration-->
<!-- validateCli is not reasonable to split as encapsulation of logic will be damaged -->
<suppress checks="CyclomaticComplexity" files="Main\.java" lines="212"/>
<suppress checks="CyclomaticComplexity" files="Main\.java" lines="249"/>
<!-- JavadocMethodCheck, JavadocStyleCheck, JavadocUtils.getJavadocTags() - deprecated -->
<suppress checks="CyclomaticComplexity" files="JavadocMethodCheck\.java"/>
<suppress checks="CyclomaticComplexity" files="JavadocStyleCheck\.java"/>
@@ -33,6 +33,7 @@
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -110,6 +111,18 @@
/** Name for the option '--debug'. */
private static final String OPTION_DEBUG_NAME = "debug";
/** Name for the option 'e'. */
private static final String OPTION_E_NAME = "e";
/** Name for the option '--exclude'. */
private static final String OPTION_EXCLUDE_NAME = "exclude";
/** Name for the option 'x'. */
private static final String OPTION_X_NAME = "x";
/** Name for the option '--xclude'. */
private static final String OPTION_XCLUDE_NAME = "xclude";
/** Name for 'xml' format. */
private static final String XML_FORMAT_NAME = "xml";
@@ -145,7 +158,8 @@ public static void main(String... args) throws IOException {
exitStatus = 0;
}
else {
final List<File> filesToProcess = getFilesToProcess(commandLine.getArgs());
final List<File> filesToProcess = getFilesToProcess(getExclusions(commandLine),
commandLine.getArgs());
// return error if something is wrong in arguments
final List<String> messages = validateCli(commandLine, filesToProcess);
@@ -203,6 +217,29 @@ private static CommandLine parseCli(String... args)
return clp.parse(buildOptions(), args);
}
/**
* Gets the list of exclusions provided through the command line argument.
* @param commandLine command line object
* @return List of exclusion patterns.
*/
private static List<Pattern> getExclusions(CommandLine commandLine) {
final List<Pattern> result = new ArrayList<>();
if (commandLine.hasOption(OPTION_E_NAME)) {
for (String s : commandLine.getOptionValues(OPTION_E_NAME)) {
result.add(
Pattern.compile("^" + Pattern.quote(new File(s).getAbsolutePath()) + "$"));
}
}
if (commandLine.hasOption(OPTION_X_NAME)) {
for (String s : commandLine.getOptionValues(OPTION_X_NAME)) {
result.add(Pattern.compile(s));
}
}
return result;
}
/**
* Do validation of Command line options.
* @param cmdLine command line object
@@ -471,14 +508,16 @@ else if (PLAIN_FORMAT_NAME.equals(format)) {
/**
* Determines the files to process.
* @param patternsToExclude The list of directory patterns to exclude from searching.
* @param filesToProcess
* arguments that were not processed yet but shall be
* @return list of files to process
*/
private static List<File> getFilesToProcess(String... filesToProcess) {
private static List<File> getFilesToProcess(List<Pattern> patternsToExclude,
String... filesToProcess) {
final List<File> files = Lists.newLinkedList();
for (String element : filesToProcess) {
files.addAll(listFiles(new File(element)));
files.addAll(listFiles(new File(element), patternsToExclude));
}
return files;
@@ -489,20 +528,33 @@ else if (PLAIN_FORMAT_NAME.equals(format)) {
* list. Subdirectories are also traversed.
* @param node
* the node to process
* @param patternsToExclude The list of directory patterns to exclude from searching.
* @return found files
*/
private static List<File> listFiles(File node) {
private static List<File> listFiles(File node, List<Pattern> patternsToExclude) {
// could be replaced with org.apache.commons.io.FileUtils.list() method
// if only we add commons-io library
final List<File> result = Lists.newLinkedList();
if (node.canRead()) {
if (node.isDirectory()) {
final File[] files = node.listFiles();
// listFiles() can return null, so we need to check it
if (files != null) {
for (File element : files) {
result.addAll(listFiles(element));
final String path = node.getAbsolutePath();
boolean allow = true;
for (Pattern pattern : patternsToExclude) {
if (pattern.matcher(path).find()) {
allow = false;
break;
}
}
if (allow) {
final File[] files = node.listFiles();
// listFiles() can return null, so we need to check it
if (files != null) {
for (File element : files) {
result.addAll(listFiles(element, patternsToExclude));
}
}
}
}
@@ -544,6 +596,10 @@ private static Options buildOptions() {
"Print full Abstract Syntax Tree of the file");
options.addOption(OPTION_D_NAME, OPTION_DEBUG_NAME, false,
"Print all debug logging of CheckStyle utility");
options.addOption(OPTION_E_NAME, OPTION_EXCLUDE_NAME, true,
"Directory path to exclude from CheckStyle");
options.addOption(OPTION_X_NAME, OPTION_XCLUDE_NAME, true,
"Regular expression of directory to exclude from CheckStyle");
return options;
}
@@ -32,12 +32,15 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
@@ -61,6 +64,7 @@
+ " file...%n"
+ " -c <arg> Sets the check configuration file to use.%n"
+ " -d,--debug Print all debug logging of CheckStyle utility%n"
+ " -e,--exclude <arg> Directory path to exclude from CheckStyle%n"
+ " -f <arg> Sets the output format. (plain|xml). Defaults to"
+ " plain%n"
+ " -j,--javadocTree Print Parse tree of the Javadoc comment%n"
@@ -70,7 +74,8 @@
+ " -t,--tree Print Abstract Syntax Tree(AST) of the file%n"
+ " -T,--treeWithComments Print Abstract Syntax Tree(AST) of the file"
+ " including comments%n"
+ " -v Print product version and exit%n");
+ " -v Print product version and exit%n"
+ " -x,--xclude <arg> Regular expression of directory to exclude from CheckStyle%n");
private static Logger logger;
private static Handler[] handlers;
@@ -595,30 +600,31 @@ public void checkAssertion() throws IOException {
@Test
@SuppressWarnings("unchecked")
public void testListFilesNotFile() throws Exception {
final Method method = Main.class.getDeclaredMethod("listFiles", File.class);
final Method method = Main.class.getDeclaredMethod("listFiles", File.class, List.class);
method.setAccessible(true);
final File fileMock = mock(File.class);
when(fileMock.canRead()).thenReturn(true);
when(fileMock.isDirectory()).thenReturn(false);
when(fileMock.isFile()).thenReturn(false);
final List<File> result = (List<File>) method.invoke(null, fileMock);
final List<File> result = (List<File>) method.invoke(null, fileMock, null);
assertEquals(0, result.size());
}
@Test
@SuppressWarnings("unchecked")
public void testListFilesDirectoryWithNull() throws Exception {
final Method method = Main.class.getDeclaredMethod("listFiles", File.class);
final Method method = Main.class.getDeclaredMethod("listFiles", File.class, List.class);
method.setAccessible(true);
final File fileMock = mock(File.class);
when(fileMock.canRead()).thenReturn(true);
when(fileMock.isDirectory()).thenReturn(true);
when(fileMock.listFiles()).thenReturn(null);
final List<File> result = (List<File>) method.invoke(null, fileMock);
final List<File> result = (List<File>) method.invoke(null, fileMock,
new ArrayList<Pattern>());
assertEquals(0, result.size());
}
@@ -849,4 +855,43 @@ public void checkAssertion() {
});
Main.main("-c", "/google_checks.xml", getPath("InputMain.java"), "-d");
}
@Test
public void testExcludeOption() throws Exception {
exit.expectSystemExitWithStatus(-1);
exit.checkAssertionAfterwards(new Assertion() {
@Override
public void checkAssertion() {
assertEquals("Files to process must be specified, found 0."
+ System.lineSeparator(), systemOut.getLog());
assertEquals("", systemErr.getLog());
}
});
Main.main("-c", "/google_checks.xml", getFilePath(""), "-e", getFilePath(""));
}
@Test
public void testXcludeOption() throws Exception {
exit.expectSystemExitWithStatus(-1);
exit.checkAssertionAfterwards(new Assertion() {
@Override
public void checkAssertion() {
assertEquals("Files to process must be specified, found 0."
+ System.lineSeparator(), systemOut.getLog());
assertEquals("", systemErr.getLog());
}
});
Main.main("-c", "/google_checks.xml", getFilePath(""), "-x", ".");
}
@Test
@SuppressWarnings("unchecked")
public void testExcludeDirectoryNotMatch() throws Exception {
final Method method = Main.class.getDeclaredMethod("listFiles", File.class, List.class);
method.setAccessible(true);
final List<File> result = (List<File>) method.invoke(null, new File(getFilePath("")),
Arrays.asList(Pattern.compile("BAD_PATH")));
assertNotEquals(0, result.size());
}
}
View
@@ -102,6 +102,15 @@ java -D&lt;property&gt;=&lt;value&gt; \
<li>
<code>-d, --debug</code> - Print all debug logging of CheckStyle utility.
</li>
<li>
<code>-e, --exclude excludedDirectory</code> - Directory to exclude from
CheckStyle. The directory can be the full, absolute path, or relative to the current path.
Multiple excludes are allowed.
</li>
<li>
<code>-x, --xclude excludedDirectoryPattern</code> - Directory pattern to exclude from
CheckStyle. Multiple excludes are allowed.
</li>
<li>
<code>-v</code> - print product version and exit. Any other option is ignored.
</li>

0 comments on commit 9008440

Please sign in to comment.