Skip to content

Commit

Permalink
java: Add CheckstyleBear
Browse files Browse the repository at this point in the history
The google_checks.xml are LGPLv2 licensed and can thus be distributed
under AGPLv3 legally.

Fixes #1067
  • Loading branch information
sils committed Feb 7, 2016
1 parent c7de186 commit 9bea8fe
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .misc/deps.sh
Expand Up @@ -44,6 +44,9 @@ for dep_version in "${dep_versions[@]}" ; do

done

# Calling setup.py will download checkstyle automatically so tests may succeed
python3 setup.py --help

if [ "$CIRCLE_NODE_INDEX" = "0" ] ; then
pip install -q mkdocs
pip install -r docs/requirements.txt
Expand Down
28 changes: 28 additions & 0 deletions bears/java/CheckstyleBear.py
@@ -0,0 +1,28 @@
import re
from os.path import dirname, abspath, join

from coalib.bearlib.abstractions.Lint import Lint
from coalib.bears.LocalBear import LocalBear
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY


class CheckstyleBear(LocalBear, Lint):
executable = 'java'
google_checks = join(dirname(abspath(__file__)), 'google_checks.xml')
jar = join(dirname(abspath(__file__)), 'checkstyle.jar')

severity_map = {
"INFO": RESULT_SEVERITY.INFO,
"WARN": RESULT_SEVERITY.NORMAL}

def run(self, filename, file):
"""
Checks the code using `checkstyle` using the Google codestyle
specification.
"""
self.output_regex = re.compile(
r'\[(?P<severity>WARN|INFO)\]\s*' + re.escape(abspath(filename)) +
r':(?P<line>\d+)(:(?P<col>\d+))?:\s*'
r'(?P<message>.*?)\s*\[(?P<origin>[a-zA-Z]+?)\]')
self.arguments = '-jar ' + self.jar + ' -c ' + self.google_checks
return self.lint(filename)
Binary file added bears/java/checkstyle.jar
Binary file not shown.
210 changes: 210 additions & 0 deletions bears/java/google_checks.xml
@@ -0,0 +1,210 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<!--
Checkstyle configuration that checks the Google coding conventions from Google Java Style
that can be found at https://google.github.io/styleguide/javaguide.html.
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
To completely disable a check, just comment it out or delete it from the file.
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
-->

<module name = "Checker">
<property name="charset" value="UTF-8"/>

<property name="severity" value="warning"/>

<property name="fileExtensions" value="java, properties, xml"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>

<module name="TreeWalker">
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format" value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message" value="Avoid using corresponding octal or Unicode escape."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="100"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="AvoidStarImport"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap"/>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NeedBraces"/>
<module name="LeftCurly">
<property name="maxLineLength" value="100"/>
</module>
<module name="RightCurly"/>
<module name="RightCurly">
<property name="option" value="alone"/>
<property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<property name="allowOneCharVarInForLoop" value="true"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="2"/>
<property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="2"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="4"/>
<property name="arrayInitIndent" value="2"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="1"/>
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="specialImportsRegExp" value="com.google"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="customImportOrderRules" value="STATIC###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
</module>
<module name="MethodParamPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
</module>
<module name="AnnotationLocation">
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod">
<property name="scope" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/>
</module>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation"/>
</module>
</module>
33 changes: 33 additions & 0 deletions bears/tests/java/CheckstyleBearTest.py
@@ -0,0 +1,33 @@
import os
import sys
from queue import Queue
from shutil import which
from unittest.case import skipIf

sys.path.insert(0, ".")
import unittest
from bears.tests.LocalBearTestHelper import LocalBearTestHelper
from bears.java.CheckstyleBear import CheckstyleBear
from coalib.settings.Section import Section


@skipIf(which('java') is None, 'java is not installed')
class CheckstyleBearTest(LocalBearTestHelper):

def setUp(self):
self.section = Section("test section")
self.uut = CheckstyleBear(self.section, Queue())
self.good_file = os.path.join(os.path.dirname(__file__),
"test_files",
"CheckstyleGood.java")
self.bad_file = os.path.join(os.path.dirname(__file__),
"test_files",
"CheckstyleBad.java")

def test_run(self):
self.assertLinesValid(self.uut, [], self.good_file)
self.assertLinesInvalid(self.uut, [], self.bad_file)


if __name__ == '__main__':
unittest.main(verbosity=2)
2 changes: 2 additions & 0 deletions bears/tests/java/test_files/CheckstyleBad.java
@@ -0,0 +1,2 @@
class badly_named_class {
}
2 changes: 2 additions & 0 deletions bears/tests/java/test_files/CheckstyleGood.java
@@ -0,0 +1,2 @@
class CheckstyleGood {
}
2 changes: 1 addition & 1 deletion coalib/bearlib/abstractions/Lint.py
Expand Up @@ -100,7 +100,7 @@ def match_to_result(self, match, filename):
groups[variable] = int(groups[variable])

return Result.from_values(
origin=self,
origin=groups.get("origin", self),
message=groups.get("message", ""),
file=filename,
severity=int(groups.get("severity", RESULT_SEVERITY.NORMAL)),
Expand Down
29 changes: 28 additions & 1 deletion setup.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python3

import locale
from urllib.request import urlopen
from shutil import copyfileobj
from os.path import exists
from setuptools import setup, find_packages
import setuptools.command.build_py

Expand All @@ -16,6 +19,26 @@
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')


def download(url, filename, overwrite=False):
"""
Downloads the given URL to the given filename. If the file exists, it won't
be downloaded.
:param url: A URL to download.
:param filename: The file to store the downloaded file to.
:param overwrite: Set to True if the file should be downloaded even if it
already exists.
:return: The filename.
"""
if not exists(filename) or overwrite:
print("Downloading", filename + "...")
with urlopen(url) as response, open(filename, 'wb') as out_file:
copyfileobj(response, out_file)
print("DONE.")

return filename


class BuildPyCommand(setuptools.command.build_py.build_py):

def run(self):
Expand All @@ -29,6 +52,9 @@ def run(self):


if __name__ == "__main__":
download('http://sourceforge.net/projects/checkstyle/files/checkstyle/'
'6.15/checkstyle-6.15-all.jar',
'bears/java/checkstyle.jar')
data_files = [('.', ['coala.1']), ('.', [Constants.BUS_NAME + '.service'])]

setup(name='coala',
Expand All @@ -43,7 +69,8 @@ def run(self):
platforms='any',
packages=find_packages(exclude=["build.*", "*.tests.*", "*.tests"]),
install_requires=required,
package_data={'coalib': ['default_coafile', "VERSION"]},
package_data={'coalib': ['default_coafile', "VERSION"],
'bears.java': ['checkstyle.jar', 'google_checks.xml']},
license="AGPL v3",
data_files=data_files,
long_description="coala is a simple COde AnaLysis Application. Its "
Expand Down

1 comment on commit 9bea8fe

@WJCode
Copy link
Contributor

@WJCode WJCode commented on 9bea8fe Feb 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

Please sign in to comment.