From 8dfe9e2bdb12a8823893b99cff2d99cc688d9b53 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Tue, 3 Oct 2017 15:34:16 -0300 Subject: [PATCH 01/24] Initial commit. --- .gitignore | 3 + .gradle/4.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../4.1/fileContent/annotation-processors.bin | Bin 0 -> 19469 bytes .gradle/4.1/fileContent/fileContent.lock | Bin 0 -> 17 bytes .gradle/4.1/fileHashes/fileHashes.bin | Bin 0 -> 30497 bytes .gradle/4.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../4.1/fileHashes/resourceHashesCache.bin | Bin 0 -> 20333 bytes .gradle/4.1/taskHistory/fileSnapshots.bin | Bin 0 -> 156590 bytes .gradle/4.1/taskHistory/taskHistory.bin | Bin 0 -> 42611 bytes .gradle/4.1/taskHistory/taskHistory.lock | Bin 0 -> 17 bytes .gradle/buildOutputCleanup/built.bin | 0 .gradle/buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/cache.properties.lock | 1 + bin/codeclimate-sonar | 15 ++ build.gradle | 37 ++++ fixtures/java_lib/main/java/Library.java | 28 +++ fixtures/java_lib/test/java/LibraryTest.java | 12 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 ++++++++++++++++++ gradlew.bat | 84 +++++++++ settings.gradle | 18 ++ src/main/groovy/cc/App.groovy | 15 ++ src/test/groovy/cc/AppTest.groovy | 18 ++ 24 files changed, 410 insertions(+) create mode 100644 .gitignore create mode 100644 .gradle/4.1/fileChanges/last-build.bin create mode 100644 .gradle/4.1/fileContent/annotation-processors.bin create mode 100644 .gradle/4.1/fileContent/fileContent.lock create mode 100644 .gradle/4.1/fileHashes/fileHashes.bin create mode 100644 .gradle/4.1/fileHashes/fileHashes.lock create mode 100644 .gradle/4.1/fileHashes/resourceHashesCache.bin create mode 100644 .gradle/4.1/taskHistory/fileSnapshots.bin create mode 100644 .gradle/4.1/taskHistory/taskHistory.bin create mode 100644 .gradle/4.1/taskHistory/taskHistory.lock create mode 100644 .gradle/buildOutputCleanup/built.bin create mode 100644 .gradle/buildOutputCleanup/cache.properties create mode 100644 .gradle/buildOutputCleanup/cache.properties.lock create mode 100755 bin/codeclimate-sonar create mode 100644 build.gradle create mode 100644 fixtures/java_lib/main/java/Library.java create mode 100644 fixtures/java_lib/test/java/LibraryTest.java create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/groovy/cc/App.groovy create mode 100644 src/test/groovy/cc/AppTest.groovy diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b06599 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +**/*.class +**/.sonarlint diff --git a/.gradle/4.1/fileChanges/last-build.bin b/.gradle/4.1/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/.gradle/4.1/fileContent/annotation-processors.bin b/.gradle/4.1/fileContent/annotation-processors.bin new file mode 100644 index 0000000000000000000000000000000000000000..4e7055076a52b459db6bb0a8c6e003b08069e22b GIT binary patch literal 19469 zcmeI&`%ler9LMpm+9`>0tcaRRZgX!gDb-TK`F_9UvesymQ_(_lS>#fu36aP>wRJ>u zix$R~Be%s8T{f3!E;|x37Q!mYq&ExZ!D*sz`E zOk%(8xvaps-|1}Ox&rp%x0atgUBcJW`cU?pu@5#xmXs!v4`wgTGi;hZc4~@n#ghI0 zwRs-VGYlHx@(cDym2H|+6Bh*u*ZHwOZ7Hrz&KW$C=C`t&GsAX`|5@Wtb1FN%%HKn8 znHnHmdB$Gr;eI@^#@N0OIu7MTrw69`*rtwpDO`?Yubb@h)OG1sx?lM-`^SuJcPp-H z`-t^QGJ8`W_pGw>OKCsIne5Hyyz3TEb6wZOristyykIbNaG-N56T}J>F^` z%~{DFVDqE$w%#gGxN2b6_1|jqqI}4E;ks=0Acv~Rs^}8Be)S@I@P`8xo@K9S-zs73 z`uf)6Uj{b2(41iQ@LJodht?UkbUlvj(XCovy?yvlT7REC#wqbeLKo9w;c^6f?EKf} zk&XTXgsat^UhNzek+jN{JcfPsA??hRqNEm@zm9#4+c>Kr3#D4P@`0UyOOl4(Q^X4V zL;(~)0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$ m0Te(16hHwKK!LxlK*yKvZQ37Q=porbP@`ivU?==*uZv%WT+_w? literal 0 HcmV?d00001 diff --git a/.gradle/4.1/fileContent/fileContent.lock b/.gradle/4.1/fileContent/fileContent.lock new file mode 100644 index 0000000000000000000000000000000000000000..91658157d9847f8ac3cddb7fe02297bae3c5f2fa GIT binary patch literal 17 UcmZSH<0@gd<;Ca63=rT1063@x4*&oF literal 0 HcmV?d00001 diff --git a/.gradle/4.1/fileHashes/fileHashes.bin b/.gradle/4.1/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..86be3af3bd361d23f0d5f20fe878090b1a1369ad GIT binary patch literal 30497 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 literal 0 HcmV?d00001 diff --git a/.gradle/4.1/fileHashes/fileHashes.lock b/.gradle/4.1/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..4f1bc7247bc37ae06dc2dd8007290d72bb672b11 GIT binary patch literal 17 VcmZRs6-vDPz|Jn10Svfi001mh1Q-AS literal 0 HcmV?d00001 diff --git a/.gradle/4.1/fileHashes/resourceHashesCache.bin b/.gradle/4.1/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..25e3a4863df1acc46d2dc44bffbcd4a926651531 GIT binary patch literal 20333 zcmeI3c~Dc=9)P2jMN&3FmSQLfWs!X`Na8{jd}PHnh{zfcrAnZnKt&K_s|w26qAWtB zg0%=m3xbGjVrT`dAe5zwYzY=D1OWj{$=rMFG}oE;@0&L#Gl4rFAHUr5C3FADJ@z=9 zn!*zL!2R=B`_Caff(2j!SO6A)1z-VK02Y7+U;$VF7Jvm{0aySQfCXRySO6A)1z>^y zmje5j7b1f!M$LGo=s-Rchco|p`G6SB@4X(+osUEQ%ya|aAH<~gIiwH@9T86F0-jpl z%dPPY-GOjg8sKSuhb;E`75AXr3Gm!sCN@jm@gXCeN&vio!VFuNcHIWyjB>!aM{;h* zWmz|)b4&m)EVB+Vvt6Nx&Jh6q!<4{kL3*GY_3?n;vOROmzB01>RLg{ zK{(|%z<+F1{)Vn+K8?sT%b&0I!s3Thd9L-i>g^YQU@ZIWszQvg{B} zZvwnt+xMl4o9DL(cl;di*7b|{D9zyw2xsO4-tNa5=4UJO5KdVDyyKmJ0I&Ac1i~4e zfOn0%2cHNYTZ3{A;LrV6SM$!hX`pjt0UzPt!Kcf_*CE`=5OBWXdfsP-1R}zz+W`Ng z8~+nK^k6T-nPkAH{0-jxSa%Wqj)^|{o#v&tbp|4vAxUQG?NLT}Z3&Ndffa@I`e{lGz z=^lhLW&zi~Jlfc$T2+ej6u=FfGm5Qp4W1yJcIQ2xY_w_&xzVBG`g z90uTKJq_U}&JdLlP6-Bl)4A6vt=8{i5l%h(o~OBmOI}E0Ae{CV@NJb!CVQMMwxPTW z@a@TU2@5WhXAw@<0Gz=snpjFINE5Nq7GFne>B_SoRgJq=^`oAs$!L&;??;j(4F-VcxE#uA9a z3alZpSC5KKw3pL3ryVxFR(A?(6stuDxBExY?V1~(&2CU#g*6TuTu)M;$SG$>WrUkGasNNsN1l!um)$XfBMX~36d{gB(=}8hs&|XraH(<-7B;V^E5VDvmGeW9bv7HdqUZ?D}kro8_9aFW8-z%NAid5g^$ z?a7p-3>{G+5gSZ|3U5Up4Kd^9cg2FikD?#{c7E=K^{u=htnsHuA}^n5q1aEbpbtHF zX~G&eDu@wKI&;q8DFVq-Yc1Z2^PXF{5(JmMN#HT0!Yp zW7|^}Q}|hsgp2Vg+amAyQLHh+I_^tmQ~4KHjZ3!TH50LhM`oF%UUj|jL~2c%$Gmb2 z)+l)%HE78?G<#)c@1`3zX&;y|!&!MP?%myM67$~A3Rbm=cF%~d)>D5oBXuBBa=MLj zqmn8V?LQJTbmZpZG&3bf3(Xf_`s&~H#Tr`@76LES;DyG#&Q}vpMn7P?>F(HF*}zBq$r`VU2;1M}u^)iznktBAslAj^AO8ha_p)F>jXI$`|@4dtFOZ zvBrPD20g@G>3iqzaDF^wty!;d=mXbNb|r`HJluFtR{Cgxv3!qcub9|cb`LC_WsP5! z7>l(l&3+^`iZ#62&FlAX6gbONA2@b;W8F@yK{DJrsJ@^3bLq|LOWpRI4;b`th81bp RSLN$d+R5@)^IJtT{svm-ha&(0 literal 0 HcmV?d00001 diff --git a/.gradle/4.1/taskHistory/fileSnapshots.bin b/.gradle/4.1/taskHistory/fileSnapshots.bin new file mode 100644 index 0000000000000000000000000000000000000000..02988db62f0068db7469dd6d5a2ee308ec6230ec GIT binary patch literal 156590 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 JKCAZJ{{b{FB(VSh literal 0 HcmV?d00001 diff --git a/.gradle/4.1/taskHistory/taskHistory.lock b/.gradle/4.1/taskHistory/taskHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..a9bcab87166ae1e61e7d346e7c7cc555d1ed987f GIT binary patch literal 17 VcmZQxDWDWSy}d@50Str}001R51C{^) literal 0 HcmV?d00001 diff --git a/.gradle/buildOutputCleanup/built.bin b/.gradle/buildOutputCleanup/built.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..2d4dfc5 --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Tue Oct 03 08:48:57 BRT 2017 +gradle.version=4.1 diff --git a/.gradle/buildOutputCleanup/cache.properties.lock b/.gradle/buildOutputCleanup/cache.properties.lock new file mode 100644 index 0000000..40fdece --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties.lock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/codeclimate-sonar b/bin/codeclimate-sonar new file mode 100755 index 0000000..a0b5e1d --- /dev/null +++ b/bin/codeclimate-sonar @@ -0,0 +1,15 @@ +#!/usr/bin/env sh +set -x + +BUILD_DIR=$(dirname $0) +LIBS=$(find ${BUILD_DIR}/libs -name "*.jar" | tr "\n" ":") + +CODE_DIR=$1; shift + +java \ + -cp ${BUILD_DIR}/classes/groovy/main/:${LIBS} \ + -Djava.awt.headless=true \ + -Dsonarlint.home="${BUILD_DIR}" \ + -Dproject.home="${CODE_DIR}" \ + -Dorg.freemarker.loggerLibrary=none \ + cc.App --src "**/*.java" $@ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c104644 --- /dev/null +++ b/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'groovy' + +repositories { + jcenter() +} + +dependencies { + // Use the latest Groovy version for building this library + compile('org.codehaus.groovy:groovy-all:2.4.11') + compile('org.sonarsource.sonarlint:sonarlint-cli:2.1.0.566') { exclude group: 'org.slf4j' } + compile('org.slf4j:slf4j-api:1.6.6') + compile('org.sonarsource.java:sonar-java-plugin:4.3.0.7717') + + // Use the awesome Spock testing and specification framework + testCompile('org.spockframework:spock-core:1.0-groovy-2.4') +} + +task copyLibs(type: Copy) { + into "${buildDir}/libs" + from configurations.runtime + exclude "sonar-*-plugin*.jar" +} + +task copyPlugins(type: Copy) { + into "${buildDir}/plugins" + from configurations.runtime + include "sonar-*-plugin*.jar" +} + +task copyRunnable(type: Copy) { + into "${buildDir}" + from "bin/codeclimate-sonar" +} + +build.dependsOn(copyPlugins) +build.dependsOn(copyLibs) +build.dependsOn(copyRunnable) diff --git a/fixtures/java_lib/main/java/Library.java b/fixtures/java_lib/main/java/Library.java new file mode 100644 index 0000000..cbeaeb2 --- /dev/null +++ b/fixtures/java_lib/main/java/Library.java @@ -0,0 +1,28 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +// FIXME +public class Library { + public static void main(String[] args) { + } + + public void foo() { + for (int i = 0; i < 10; i++) { + for (int k = 0; k < 20; k++) { + System.out.println("Hello"); + } + } + + for (int i = 0; i < 10; i++) { // only references 'i' + for (int k = 0; k < 20; i++) { // references both 'i' and 'k' + System.out.println("Hello"); + } + for (int k = 0; k < 20; i++) { // references both 'i' and 'k' + System.out.println("Hello"); + } + for (int k = 0; k < 20; i++) { // references both 'i' and 'k' + System.out.println("Hello"); + } + } + } +} diff --git a/fixtures/java_lib/test/java/LibraryTest.java b/fixtures/java_lib/test/java/LibraryTest.java new file mode 100644 index 0000000..645740d --- /dev/null +++ b/fixtures/java_lib/test/java/LibraryTest.java @@ -0,0 +1,12 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +import org.junit.Test; +import static org.junit.Assert.*; + +public class LibraryTest { + @Test public void testSomeLibraryMethod() { + Library classUnderTest = new Library(); + assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 GIT binary patch literal 54708 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

_x$+l{{cH8$W#CT literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..f16d266 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..98d413e --- /dev/null +++ b/settings.gradle @@ -0,0 +1,18 @@ +/* + * This settings file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/4.1/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'gradle-groovy-app' diff --git a/src/main/groovy/cc/App.groovy b/src/main/groovy/cc/App.groovy new file mode 100644 index 0000000..2e3f133 --- /dev/null +++ b/src/main/groovy/cc/App.groovy @@ -0,0 +1,15 @@ +package cc + +import org.sonarlint.cli.Main + +class App { + String getGreeting() { + return 'Hello world.' + } + + static void main(String[] args) { + println new App().greeting + println ">>>" + Main.main(args) + } +} diff --git a/src/test/groovy/cc/AppTest.groovy b/src/test/groovy/cc/AppTest.groovy new file mode 100644 index 0000000..fc49af6 --- /dev/null +++ b/src/test/groovy/cc/AppTest.groovy @@ -0,0 +1,18 @@ +package cc +/* + * This Spock specification was generated by the Gradle 'init' task. + */ +import spock.lang.Specification + +class AppTest extends Specification { + def "application has a greeting"() { + setup: + def app = new App() + + when: + def result = app.greeting + + then: + result != null + } +} From 61aa0abe805a7ac0dba10b6331ef06716c211619 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:01:53 -0300 Subject: [PATCH 02/24] Remove unecessary files --- .gradle/4.1/fileChanges/last-build.bin | Bin 1 -> 0 bytes .../4.1/fileContent/annotation-processors.bin | Bin 19469 -> 0 bytes .gradle/4.1/fileContent/fileContent.lock | Bin 17 -> 0 bytes .gradle/4.1/fileHashes/fileHashes.bin | Bin 30497 -> 0 bytes .gradle/4.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/4.1/fileHashes/resourceHashesCache.bin | Bin 20333 -> 0 bytes .gradle/4.1/taskHistory/fileSnapshots.bin | Bin 156590 -> 0 bytes .gradle/4.1/taskHistory/taskHistory.bin | Bin 42611 -> 0 bytes .gradle/4.1/taskHistory/taskHistory.lock | Bin 17 -> 0 bytes .gradle/buildOutputCleanup/built.bin | 0 .gradle/buildOutputCleanup/cache.properties | 2 -- .../buildOutputCleanup/cache.properties.lock | 1 - 12 files changed, 3 deletions(-) delete mode 100644 .gradle/4.1/fileChanges/last-build.bin delete mode 100644 .gradle/4.1/fileContent/annotation-processors.bin delete mode 100644 .gradle/4.1/fileContent/fileContent.lock delete mode 100644 .gradle/4.1/fileHashes/fileHashes.bin delete mode 100644 .gradle/4.1/fileHashes/fileHashes.lock delete mode 100644 .gradle/4.1/fileHashes/resourceHashesCache.bin delete mode 100644 .gradle/4.1/taskHistory/fileSnapshots.bin delete mode 100644 .gradle/4.1/taskHistory/taskHistory.bin delete mode 100644 .gradle/4.1/taskHistory/taskHistory.lock delete mode 100644 .gradle/buildOutputCleanup/built.bin delete mode 100644 .gradle/buildOutputCleanup/cache.properties delete mode 100644 .gradle/buildOutputCleanup/cache.properties.lock diff --git a/.gradle/4.1/fileChanges/last-build.bin b/.gradle/4.1/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/.gradle/4.1/fileContent/annotation-processors.bin b/.gradle/4.1/fileContent/annotation-processors.bin deleted file mode 100644 index 4e7055076a52b459db6bb0a8c6e003b08069e22b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19469 zcmeI&`%ler9LMpm+9`>0tcaRRZgX!gDb-TK`F_9UvesymQ_(_lS>#fu36aP>wRJ>u zix$R~Be%s8T{f3!E;|x37Q!mYq&ExZ!D*sz`E zOk%(8xvaps-|1}Ox&rp%x0atgUBcJW`cU?pu@5#xmXs!v4`wgTGi;hZc4~@n#ghI0 zwRs-VGYlHx@(cDym2H|+6Bh*u*ZHwOZ7Hrz&KW$C=C`t&GsAX`|5@Wtb1FN%%HKn8 znHnHmdB$Gr;eI@^#@N0OIu7MTrw69`*rtwpDO`?Yubb@h)OG1sx?lM-`^SuJcPp-H z`-t^QGJ8`W_pGw>OKCsIne5Hyyz3TEb6wZOristyykIbNaG-N56T}J>F^` z%~{DFVDqE$w%#gGxN2b6_1|jqqI}4E;ks=0Acv~Rs^}8Be)S@I@P`8xo@K9S-zs73 z`uf)6Uj{b2(41iQ@LJodht?UkbUlvj(XCovy?yvlT7REC#wqbeLKo9w;c^6f?EKf} zk&XTXgsat^UhNzek+jN{JcfPsA??hRqNEm@zm9#4+c>Kr3#D4P@`0UyOOl4(Q^X4V zL;(~)0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$ m0Te(16hHwKK!LxlK*yKvZQ37Q=porbP@`ivU?==*uZv%WT+_w? diff --git a/.gradle/4.1/fileContent/fileContent.lock b/.gradle/4.1/fileContent/fileContent.lock deleted file mode 100644 index 91658157d9847f8ac3cddb7fe02297bae3c5f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZSH<0@gd<;Ca63=rT1063@x4*&oF diff --git a/.gradle/4.1/fileHashes/fileHashes.bin b/.gradle/4.1/fileHashes/fileHashes.bin deleted file mode 100644 index 86be3af3bd361d23f0d5f20fe878090b1a1369ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30497 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 diff --git a/.gradle/4.1/fileHashes/fileHashes.lock b/.gradle/4.1/fileHashes/fileHashes.lock deleted file mode 100644 index 4f1bc7247bc37ae06dc2dd8007290d72bb672b11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZRs6-vDPz|Jn10Svfi001mh1Q-AS diff --git a/.gradle/4.1/fileHashes/resourceHashesCache.bin b/.gradle/4.1/fileHashes/resourceHashesCache.bin deleted file mode 100644 index 25e3a4863df1acc46d2dc44bffbcd4a926651531..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20333 zcmeI3c~Dc=9)P2jMN&3FmSQLfWs!X`Na8{jd}PHnh{zfcrAnZnKt&K_s|w26qAWtB zg0%=m3xbGjVrT`dAe5zwYzY=D1OWj{$=rMFG}oE;@0&L#Gl4rFAHUr5C3FADJ@z=9 zn!*zL!2R=B`_Caff(2j!SO6A)1z-VK02Y7+U;$VF7Jvm{0aySQfCXRySO6A)1z>^y zmje5j7b1f!M$LGo=s-Rchco|p`G6SB@4X(+osUEQ%ya|aAH<~gIiwH@9T86F0-jpl z%dPPY-GOjg8sKSuhb;E`75AXr3Gm!sCN@jm@gXCeN&vio!VFuNcHIWyjB>!aM{;h* zWmz|)b4&m)EVB+Vvt6Nx&Jh6q!<4{kL3*GY_3?n;vOROmzB01>RLg{ zK{(|%z<+F1{)Vn+K8?sT%b&0I!s3Thd9L-i>g^YQU@ZIWszQvg{B} zZvwnt+xMl4o9DL(cl;di*7b|{D9zyw2xsO4-tNa5=4UJO5KdVDyyKmJ0I&Ac1i~4e zfOn0%2cHNYTZ3{A;LrV6SM$!hX`pjt0UzPt!Kcf_*CE`=5OBWXdfsP-1R}zz+W`Ng z8~+nK^k6T-nPkAH{0-jxSa%Wqj)^|{o#v&tbp|4vAxUQG?NLT}Z3&Ndffa@I`e{lGz z=^lhLW&zi~Jlfc$T2+ej6u=FfGm5Qp4W1yJcIQ2xY_w_&xzVBG`g z90uTKJq_U}&JdLlP6-Bl)4A6vt=8{i5l%h(o~OBmOI}E0Ae{CV@NJb!CVQMMwxPTW z@a@TU2@5WhXAw@<0Gz=snpjFINE5Nq7GFne>B_SoRgJq=^`oAs$!L&;??;j(4F-VcxE#uA9a z3alZpSC5KKw3pL3ryVxFR(A?(6stuDxBExY?V1~(&2CU#g*6TuTu)M;$SG$>WrUkGasNNsN1l!um)$XfBMX~36d{gB(=}8hs&|XraH(<-7B;V^E5VDvmGeW9bv7HdqUZ?D}kro8_9aFW8-z%NAid5g^$ z?a7p-3>{G+5gSZ|3U5Up4Kd^9cg2FikD?#{c7E=K^{u=htnsHuA}^n5q1aEbpbtHF zX~G&eDu@wKI&;q8DFVq-Yc1Z2^PXF{5(JmMN#HT0!Yp zW7|^}Q}|hsgp2Vg+amAyQLHh+I_^tmQ~4KHjZ3!TH50LhM`oF%UUj|jL~2c%$Gmb2 z)+l)%HE78?G<#)c@1`3zX&;y|!&!MP?%myM67$~A3Rbm=cF%~d)>D5oBXuBBa=MLj zqmn8V?LQJTbmZpZG&3bf3(Xf_`s&~H#Tr`@76LES;DyG#&Q}vpMn7P?>F(HF*}zBq$r`VU2;1M}u^)iznktBAslAj^AO8ha_p)F>jXI$`|@4dtFOZ zvBrPD20g@G>3iqzaDF^wty!;d=mXbNb|r`HJluFtR{Cgxv3!qcub9|cb`LC_WsP5! z7>l(l&3+^`iZ#62&FlAX6gbONA2@b;W8F@yK{DJrsJ@^3bLq|LOWpRI4;b`th81bp RSLN$d+R5@)^IJtT{svm-ha&(0 diff --git a/.gradle/4.1/taskHistory/fileSnapshots.bin b/.gradle/4.1/taskHistory/fileSnapshots.bin deleted file mode 100644 index 02988db62f0068db7469dd6d5a2ee308ec6230ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156590 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 JKCAZJ{{b{FB(VSh diff --git a/.gradle/4.1/taskHistory/taskHistory.lock b/.gradle/4.1/taskHistory/taskHistory.lock deleted file mode 100644 index a9bcab87166ae1e61e7d346e7c7cc555d1ed987f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZQxDWDWSy}d@50Str}001R51C{^) diff --git a/.gradle/buildOutputCleanup/built.bin b/.gradle/buildOutputCleanup/built.bin deleted file mode 100644 index e69de29..0000000 diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 2d4dfc5..0000000 --- a/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Tue Oct 03 08:48:57 BRT 2017 -gradle.version=4.1 diff --git a/.gradle/buildOutputCleanup/cache.properties.lock b/.gradle/buildOutputCleanup/cache.properties.lock deleted file mode 100644 index 40fdece..0000000 --- a/.gradle/buildOutputCleanup/cache.properties.lock +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 7708991885dc05a4324bc9d8e1e60eb457890873 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:02:59 -0300 Subject: [PATCH 03/24] Ignore .gradle and IntelliJ files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 1b06599..14135be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +.gradle/ build/ **/*.class **/.sonarlint +*.iml +*.ipr +*.iws From 6f85636977776e71a04aeb8982e04bb55716ce09 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:14:41 -0300 Subject: [PATCH 04/24] Use specific versions of sonarlint-core and sonarlit-client-api that support newer attributes and are compatible with current sonarlint-cli implementation --- build.gradle | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index c104644..0126e95 100644 --- a/build.gradle +++ b/build.gradle @@ -1,20 +1,9 @@ -apply plugin: 'groovy' +apply plugin: "groovy" repositories { jcenter() } -dependencies { - // Use the latest Groovy version for building this library - compile('org.codehaus.groovy:groovy-all:2.4.11') - compile('org.sonarsource.sonarlint:sonarlint-cli:2.1.0.566') { exclude group: 'org.slf4j' } - compile('org.slf4j:slf4j-api:1.6.6') - compile('org.sonarsource.java:sonar-java-plugin:4.3.0.7717') - - // Use the awesome Spock testing and specification framework - testCompile('org.spockframework:spock-core:1.0-groovy-2.4') -} - task copyLibs(type: Copy) { into "${buildDir}/libs" from configurations.runtime @@ -35,3 +24,14 @@ task copyRunnable(type: Copy) { build.dependsOn(copyPlugins) build.dependsOn(copyLibs) build.dependsOn(copyRunnable) + +dependencies { + compile("org.sonarsource.sonarlint.core:sonarlint-core:2.10.0.367") + compile("org.sonarsource.sonarlint.core:sonarlint-client-api:2.10.0.367") + compile("org.sonarsource.sonarlint:sonarlint-cli:2.1.0.566") + + // Plugins + compile("org.sonarsource.java:sonar-java-plugin:4.3.0.7717") + + testCompile("junit:junit:4.12") +} \ No newline at end of file From 21d6b538c2f96d6388fe22ffff6293d4834b6720 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:05:27 -0300 Subject: [PATCH 05/24] Override Sonarlint's classes to add CC's JsonReport --- src/main/groovy/cc/App.groovy | 15 ---- src/main/java/cc/App.java | 9 ++ src/main/java/cc/JsonReport.java | 84 ++++++++++++++++++ .../java/org/sonarlint/cli/CustomMain.java | 86 +++++++++++++++++++ src/test/groovy/cc/AppTest.groovy | 18 ---- 5 files changed, 179 insertions(+), 33 deletions(-) delete mode 100644 src/main/groovy/cc/App.groovy create mode 100644 src/main/java/cc/App.java create mode 100644 src/main/java/cc/JsonReport.java create mode 100644 src/main/java/org/sonarlint/cli/CustomMain.java delete mode 100644 src/test/groovy/cc/AppTest.groovy diff --git a/src/main/groovy/cc/App.groovy b/src/main/groovy/cc/App.groovy deleted file mode 100644 index 2e3f133..0000000 --- a/src/main/groovy/cc/App.groovy +++ /dev/null @@ -1,15 +0,0 @@ -package cc - -import org.sonarlint.cli.Main - -class App { - String getGreeting() { - return 'Hello world.' - } - - static void main(String[] args) { - println new App().greeting - println ">>>" - Main.main(args) - } -} diff --git a/src/main/java/cc/App.java b/src/main/java/cc/App.java new file mode 100644 index 0000000..5ebb316 --- /dev/null +++ b/src/main/java/cc/App.java @@ -0,0 +1,9 @@ +package cc; + +import org.sonarlint.cli.CustomMain; + +public class App { + public static void main(String[] args) { + CustomMain.main(args); + } +} diff --git a/src/main/java/cc/JsonReport.java b/src/main/java/cc/JsonReport.java new file mode 100644 index 0000000..d44ad88 --- /dev/null +++ b/src/main/java/cc/JsonReport.java @@ -0,0 +1,84 @@ +package cc; + +import com.google.gson.JsonObject; +import com.google.gson.JsonArray; +import java.io.PrintStream; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Arrays; +import java.util.function.Function; +import org.sonarlint.cli.util.Logger; +import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; +import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; +import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; +import org.sonarsource.sonarlint.core.tracking.Trackable; + +public class JsonReport implements org.sonarlint.cli.report.Reporter { + + private static final List VALID_RULE_DETAIL_TYPES = Arrays.asList( + "BUG", + "VULNERABILITY" + ); + + + @Override + public void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer) { + for (Trackable trackable : trackables) { + Issue issue = trackable.getIssue(); + RuleDetails ruleDetails = ruleDescriptionProducer.apply(issue.getRuleKey()); + + if (VALID_RULE_DETAIL_TYPES.contains(ruleDetails.getType())) { + JsonObject json = new JsonObject(); + json.addProperty("type", "issue"); + json.addProperty("check_name", issue.getRuleKey()); + json.addProperty("severity", ruleDetails.getSeverity().toLowerCase()); + json.addProperty("description", issue.getMessage()); + + JsonObject content = new JsonObject(); + json.add("content", content); + content.addProperty("body", ruleDetails.getHtmlDescription()); + // // ruleDetails.getExtendedDescription(); + + JsonObject location = new JsonObject(); + json.add("location", location); + + // Code Climate CLI expects relative path to file + location.addProperty("path", issue.getInputFile().getPath().replaceFirst("^/code-read-write/", "")); + + JsonObject lines = new JsonObject(); + location.add("lines", lines); + + if (issue.getStartLine() != null) { + lines.addProperty("begin", issue.getStartLine()); + + if (issue.getEndLine() != null) { + lines.addProperty("end", issue.getEndLine()); + } else { + lines.addProperty("end", 1); + } + } else { + lines.addProperty("begin", 1); + lines.addProperty("end", 1); + } + + String category; + switch (ruleDetails.getType()) { + case "VULNERABILITY": { + category = "Security"; + break; + } + default: { + category = "Bug Risk"; + break; + } + } + JsonArray categories = new JsonArray(); + categories.add(category); + json.add("categories", categories); + + System.out.println(json.toString() + "\0"); + } + } + } +} diff --git a/src/main/java/org/sonarlint/cli/CustomMain.java b/src/main/java/org/sonarlint/cli/CustomMain.java new file mode 100644 index 0000000..e780acb --- /dev/null +++ b/src/main/java/org/sonarlint/cli/CustomMain.java @@ -0,0 +1,86 @@ +package org.sonarlint.cli; + +import cc.JsonReport; +import org.sonarlint.cli.analysis.SonarLintFactory; +import org.sonarlint.cli.config.ConfigurationReader; +import org.sonarlint.cli.report.ReportFactory; +import org.sonarlint.cli.report.Reporter; +import org.sonarlint.cli.util.Logger; +import org.sonarlint.cli.util.System2; + +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.ParseException; +import java.util.Arrays; +import java.util.List; + +import static org.sonarlint.cli.SonarProperties.PROJECT_HOME; + + +public class CustomMain extends org.sonarlint.cli.Main { + static final int SUCCESS = 0; + static final int ERROR = 1; + private static final Logger LOGGER = Logger.get(); + + public CustomMain(Options opts, SonarLintFactory sonarLintFactory, ReportFactory reportFactory, InputFileFinder fileFinder, Path projectHome) { + super(opts, sonarLintFactory, reportFactory, fileFinder, projectHome); + } + + public static void main(String[] args) { + execute(args, System2.INSTANCE); + } + + static void execute(String[] args, System2 system) { + Options parsedOpts; + try { + parsedOpts = Options.parse(args); + } catch (ParseException e) { + LOGGER.error("Error parsing arguments: " + e.getMessage(), e); + Options.printUsage(); + system.exit(ERROR); + return; + } + + Charset charset; + try { + if (parsedOpts.charset() != null) { + charset = Charset.forName(parsedOpts.charset()); + } else { + charset = Charset.defaultCharset(); + } + } catch (Exception e) { + LOGGER.error("Error creating charset: " + parsedOpts.charset(), e); + system.exit(ERROR); + return; + } + + InputFileFinder fileFinder = new InputFileFinder(parsedOpts.src(), parsedOpts.tests(), parsedOpts.exclusions(), charset); + ReportFactory reportFactory = new CustomReportFactory(charset); + ConfigurationReader reader = new ConfigurationReader(); + SonarLintFactory sonarLintFactory = new SonarLintFactory(reader); + + int ret = new CustomMain(parsedOpts, sonarLintFactory, reportFactory, fileFinder, getProjectHome(system)).run(); + system.exit(ret); + return; + } + + private static Path getProjectHome(System2 system) { + String projectHome = system.getProperty(PROJECT_HOME); + if (projectHome == null) { + throw new IllegalStateException("Can't find project home. System property not set: " + PROJECT_HOME); + } + return Paths.get(projectHome); + } + + private static class CustomReportFactory extends ReportFactory { + public CustomReportFactory(Charset charset) { + super(charset); + } + + @Override + public List createReporters(Path basePath) { + return Arrays.asList(new JsonReport()); + } + } +} diff --git a/src/test/groovy/cc/AppTest.groovy b/src/test/groovy/cc/AppTest.groovy deleted file mode 100644 index fc49af6..0000000 --- a/src/test/groovy/cc/AppTest.groovy +++ /dev/null @@ -1,18 +0,0 @@ -package cc -/* - * This Spock specification was generated by the Gradle 'init' task. - */ -import spock.lang.Specification - -class AppTest extends Specification { - def "application has a greeting"() { - setup: - def app = new App() - - when: - def result = app.greeting - - then: - result != null - } -} From 02ac0f58b2e93b60a26ca6cb36c9ed991a06ac34 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:07:20 -0300 Subject: [PATCH 06/24] Give classpath priority to sonalint-core and sonarlint-client-api --- bin/codeclimate-sonar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/codeclimate-sonar b/bin/codeclimate-sonar index a0b5e1d..15cdcdc 100755 --- a/bin/codeclimate-sonar +++ b/bin/codeclimate-sonar @@ -1,13 +1,13 @@ #!/usr/bin/env sh -set -x BUILD_DIR=$(dirname $0) LIBS=$(find ${BUILD_DIR}/libs -name "*.jar" | tr "\n" ":") +CORE=$(find ${BUILD_DIR}/libs -name "sonarlint-core*.jar" -or -name "sonarlint-client-api*.jar" | tr "\n" ":") CODE_DIR=$1; shift java \ - -cp ${BUILD_DIR}/classes/groovy/main/:${LIBS} \ + -cp ${CORE}:${LIBS} \ -Djava.awt.headless=true \ -Dsonarlint.home="${BUILD_DIR}" \ -Dproject.home="${CODE_DIR}" \ From 6bdd3d58aa7dc92aec069aac12db462eea1cb85c Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 10:18:57 -0300 Subject: [PATCH 07/24] Keep license header --- .../java/org/sonarlint/cli/CustomMain.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/org/sonarlint/cli/CustomMain.java b/src/main/java/org/sonarlint/cli/CustomMain.java index e780acb..d1f2e2e 100644 --- a/src/main/java/org/sonarlint/cli/CustomMain.java +++ b/src/main/java/org/sonarlint/cli/CustomMain.java @@ -1,3 +1,22 @@ +/* + * SonarLint CLI + * Copyright (C) 2016-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ package org.sonarlint.cli; import cc.JsonReport; From 174fecfb3b7b219815701647448fa08dc02d207b Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 11:44:08 -0300 Subject: [PATCH 08/24] Move log messages to stderr --- .../java/org/sonarlint/cli/util/Logger.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/main/java/org/sonarlint/cli/util/Logger.java diff --git a/src/main/java/org/sonarlint/cli/util/Logger.java b/src/main/java/org/sonarlint/cli/util/Logger.java new file mode 100644 index 0000000..c1d31a8 --- /dev/null +++ b/src/main/java/org/sonarlint/cli/util/Logger.java @@ -0,0 +1,98 @@ +/* + * SonarLint CLI + * Copyright (C) 2016-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarlint.cli.util; + +import java.io.PrintStream; + +public class Logger { + private static volatile Logger instance; + private boolean debugEnabled = false; + private boolean displayStackTrace = false; + private PrintStream stdOut; + private PrintStream stdErr; + + private Logger() { + this.stdErr = System.err; + this.stdOut = System.out; + } + + public Logger(PrintStream stdOut, PrintStream stdErr) { + this.stdErr = stdErr; + this.stdOut = stdOut; + } + + public static Logger get() { + if (instance == null) { + instance = new Logger(); + } + return instance; + } + + public static void set(PrintStream stdOut, PrintStream stdErr) { + get().stdOut = stdOut; + get().stdErr = stdErr; + } + + public void setDebugEnabled(boolean debugEnabled) { + this.debugEnabled = debugEnabled; + } + + public void setDisplayStackTrace(boolean displayStackTrace) { + this.displayStackTrace = displayStackTrace; + } + + public boolean isDebugEnabled() { + return debugEnabled; + } + + public void debug(String message) { + if (isDebugEnabled()) { + stdErr.println("DEBUG: " + message); + } + } + + public void debug(String message, Throwable t) { + if (isDebugEnabled()) { + stdErr.println("DEBUG: " + message); + if (displayStackTrace) { + t.printStackTrace(stdErr); + } + } + } + + public void info(String message) { + stdErr.println("INFO: " + message); + } + + public void warn(String message) { + stdErr.println("WARN: " + message); + } + + public void error(String message) { + stdErr.println("ERROR: " + message); + } + + public void error(String message, Throwable t) { + stdErr.println("ERROR: " + message); + if (displayStackTrace) { + t.printStackTrace(stdErr); + } + } +} From 115ebd168cddc52167ff1805721cca4aeccec471 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 11:45:01 -0300 Subject: [PATCH 09/24] Give app a proper name --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 98d413e..d3b36c9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,4 +15,4 @@ include 'api' include 'services:webservice' */ -rootProject.name = 'gradle-groovy-app' +rootProject.name = 'codeclimate-sonar-java' From c38ac3943562f4fb395c41ea619edf7625d7afb3 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 11:45:47 -0300 Subject: [PATCH 10/24] Make app classes first priority on classpath - so we can override whatever we need --- bin/codeclimate-sonar | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/codeclimate-sonar b/bin/codeclimate-sonar index 15cdcdc..53d1fda 100755 --- a/bin/codeclimate-sonar +++ b/bin/codeclimate-sonar @@ -1,13 +1,14 @@ #!/usr/bin/env sh BUILD_DIR=$(dirname $0) +APP=$(find ${BUILD_DIR}/libs -name "codeclimate*.jar" | tr "\n" ":") LIBS=$(find ${BUILD_DIR}/libs -name "*.jar" | tr "\n" ":") CORE=$(find ${BUILD_DIR}/libs -name "sonarlint-core*.jar" -or -name "sonarlint-client-api*.jar" | tr "\n" ":") CODE_DIR=$1; shift java \ - -cp ${CORE}:${LIBS} \ + -cp ${APP}:${CORE}:${LIBS} \ -Djava.awt.headless=true \ -Dsonarlint.home="${BUILD_DIR}" \ -Dproject.home="${CODE_DIR}" \ From c6346437f05cdada8b4e9ad58e41857097427924 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 11:46:13 -0300 Subject: [PATCH 11/24] Docker setup --- Dockerfile | 26 ++++++++++++++++++++++++++ Makefile | 11 +++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Dockerfile create mode 100644 Makefile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..87d5d4b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM java:8-jdk-alpine + +MAINTAINER Code Climate + +RUN adduser -u 9000 -D app +VOLUME /code + +# Create a writeable directory for the code +RUN mkdir -p /code-read-write +RUN chown -R app:app /code-read-write +RUN chmod -R 777 /code-read-write + +COPY . /usr/src/app +RUN chown -R app:app /usr/src/app + +WORKDIR /usr/src/app +RUN ./gradlew clean build + +# Increase Java memory limits +ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" + +# Switch to app user, copy code to writable directory, and run the engine +USER app +ENTRYPOINT [] +WORKDIR /code-read-write +CMD cp -R /code/* . && /usr/src/app/build/codeclimate-sonar /code-read-write diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba3b085 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +.PHONY: image test + +IMAGE_NAME ?= codeclimate/codeclimate-sonar-java +DOCKER_RUN_MOUNTED = docker run --rm -w /usr/src/app -v $(PWD):/usr/src/app + +image: + docker build --rm -t $(IMAGE_NAME) . + +test: image + docker run -ti -v $(PWD)/fixtures:/code $(IMAGE_NAME) + From 359b56021b6237539e67c800d0e4a402f7810cea Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 12:08:12 -0300 Subject: [PATCH 12/24] Save a few MBs on docker image --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 87d5d4b..feb7482 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ -FROM java:8-jdk-alpine +FROM gradle:jdk8-alpine MAINTAINER Code Climate +USER root RUN adduser -u 9000 -D app VOLUME /code @@ -10,11 +11,13 @@ RUN mkdir -p /code-read-write RUN chown -R app:app /code-read-write RUN chmod -R 777 /code-read-write +ENV GRADLE_USER_HOME=/opt/gradle + COPY . /usr/src/app RUN chown -R app:app /usr/src/app WORKDIR /usr/src/app -RUN ./gradlew clean build +RUN gradle clean build # Increase Java memory limits ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" From 7e908b8f07fabba80b558cb7ed8efa950e8b0a0f Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 12:38:59 -0300 Subject: [PATCH 13/24] Optimize docker layers by caching project dependencies --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index feb7482..c4ff019 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,10 @@ RUN chmod -R 777 /code-read-write ENV GRADLE_USER_HOME=/opt/gradle +# Cache dependencies +COPY ./build.gradle /opt/ +RUN cd /opt && gradle build + COPY . /usr/src/app RUN chown -R app:app /usr/src/app From 0de0f6f0d261233c5dcfe3cbcc88195d88eebd71 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 15:16:47 -0300 Subject: [PATCH 14/24] Add sanitity check test --- Dockerfile | 2 +- Makefile | 3 +- build.gradle | 17 +++++++-- src/test/java/cc/SanityCheckTest.java | 53 +++++++++++++++++++++++++++ src/test/java/cc/Shell.java | 44 ++++++++++++++++++++++ 5 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 src/test/java/cc/SanityCheckTest.java create mode 100644 src/test/java/cc/Shell.java diff --git a/Dockerfile b/Dockerfile index c4ff019..5d1151e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY . /usr/src/app RUN chown -R app:app /usr/src/app WORKDIR /usr/src/app -RUN gradle clean build +RUN gradle clean build -x test # Increase Java memory limits ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" diff --git a/Makefile b/Makefile index ba3b085..cad49b6 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,10 @@ .PHONY: image test IMAGE_NAME ?= codeclimate/codeclimate-sonar-java -DOCKER_RUN_MOUNTED = docker run --rm -w /usr/src/app -v $(PWD):/usr/src/app image: docker build --rm -t $(IMAGE_NAME) . test: image - docker run -ti -v $(PWD)/fixtures:/code $(IMAGE_NAME) + docker run --rm -ti -w /usr/src/app -u root $(IMAGE_NAME) gradle clean test diff --git a/build.gradle b/build.gradle index 0126e95..622ab3d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -apply plugin: "groovy" +apply plugin: "java" repositories { jcenter() @@ -21,9 +21,10 @@ task copyRunnable(type: Copy) { from "bin/codeclimate-sonar" } -build.dependsOn(copyPlugins) -build.dependsOn(copyLibs) -build.dependsOn(copyRunnable) +task infra(dependsOn: ["copyPlugins", "copyLibs", "copyRunnable", "jar"]) + +build.dependsOn(infra) +test.dependsOn(infra) dependencies { compile("org.sonarsource.sonarlint.core:sonarlint-core:2.10.0.367") @@ -33,5 +34,13 @@ dependencies { // Plugins compile("org.sonarsource.java:sonar-java-plugin:4.3.0.7717") + testCompile("org.assertj:assertj-core:2.8.0") testCompile("junit:junit:4.12") +} + +test { + outputs.upToDateWhen { false } + testLogging { + exceptionFormat "full" + } } \ No newline at end of file diff --git a/src/test/java/cc/SanityCheckTest.java b/src/test/java/cc/SanityCheckTest.java new file mode 100644 index 0000000..8829ce3 --- /dev/null +++ b/src/test/java/cc/SanityCheckTest.java @@ -0,0 +1,53 @@ +package cc; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class SanityCheckTest { + @Test + public void executeJavaLibFixture() throws Exception { + List expectedOutput = Arrays.asList("{\"type\":\"issue\"," + + "\"check_name\":\"squid:S1994\"," + + "\"severity\":\"major\"," + + "\"description\":\"This loop's stop condition tests \\\"k\\\" but the incrementer updates \\\"i\\\".\"," + + "\"content\":{\"body\":\"

It is almost always an error when a for loop's stop condition and incrementer don't act on the same variable. Even when it is not," + + " it\\ncould confuse future maintainers of the code," + + " and should be avoided.

\\n

Noncompliant Code Example

\\n
\\nfor (i = 0; i < 10; j++) {  // Noncompliant\\n  // ...\\n}\\n
\\n

Compliant Solution

\\n
\\nfor (i = 0; i < 10; i++) {\\n  // ...\\n}\\n
\"}," + + "\"location\":{\"path\":\"fixtures/java_lib/main/java/Library.java\"," + + "\"lines\":{\"begin\":17," + + "\"end\":17}}," + + "\"categories\":[\"Bug Risk\"]}\u0000", + "{\"type\":\"issue\"," + + "\"check_name\":\"squid:S1994\"," + + "\"severity\":\"major\"," + + "\"description\":\"This loop's stop condition tests \\\"k\\\" but the incrementer updates \\\"i\\\".\"," + + "\"content\":{\"body\":\"

It is almost always an error when a for loop's stop condition and incrementer don't act on the same variable. Even when it is not," + + " it\\ncould confuse future maintainers of the code," + + " and should be avoided.

\\n

Noncompliant Code Example

\\n
\\nfor (i = 0; i < 10; j++) {  // Noncompliant\\n  // ...\\n}\\n
\\n

Compliant Solution

\\n
\\nfor (i = 0; i < 10; i++) {\\n  // ...\\n}\\n
\"}," + + "\"location\":{\"path\":\"fixtures/java_lib/main/java/Library.java\"," + + "\"lines\":{\"begin\":20," + + "\"end\":20}}," + + "\"categories\":[\"Bug Risk\"]}\u0000", + "{\"type\":\"issue\"," + + "\"check_name\":\"squid:S1994\"," + + "\"severity\":\"major\"," + + "\"description\":\"This loop's stop condition tests \\\"k\\\" but the incrementer updates \\\"i\\\".\"," + + "\"content\":{\"body\":\"

It is almost always an error when a for loop's stop condition and incrementer don't act on the same variable. Even when it is not," + + " it\\ncould confuse future maintainers of the code," + + " and should be avoided.

\\n

Noncompliant Code Example

\\n
\\nfor (i = 0; i < 10; j++) {  // Noncompliant\\n  // ...\\n}\\n
\\n

Compliant Solution

\\n
\\nfor (i = 0; i < 10; i++) {\\n  // ...\\n}\\n
\"}," + + "\"location\":{\"path\":\"fixtures/java_lib/main/java/Library.java\"," + + "\"lines\":{\"begin\":23," + + "\"end\":23}}," + + "\"categories\":[\"Bug Risk\"]}\u0000"); + + Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/"); + + assertThat(process.exitCode).isEqualTo(0); + assertThat(process.stdout).contains(expectedOutput); + } +} diff --git a/src/test/java/cc/Shell.java b/src/test/java/cc/Shell.java new file mode 100644 index 0000000..84fbe6f --- /dev/null +++ b/src/test/java/cc/Shell.java @@ -0,0 +1,44 @@ +package cc; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Shell { + public static Process execute(String command) throws IOException, InterruptedException { + java.lang.Process process = Runtime.getRuntime().exec(command); + StringBuilder stdout = consumeBuffer(process.getInputStream()); + StringBuilder stderr = consumeBuffer(process.getErrorStream()); + + process.waitFor(); + + Process localProcess = new Process(process.exitValue(), stdout.toString(), stderr.toString()); + if (localProcess.exitCode != 0) { + System.err.println(localProcess.stderr); + } + return localProcess; + } + + private static StringBuilder consumeBuffer(InputStream stream) throws IOException { + StringBuilder stdout = new StringBuilder(); + BufferedReader in = new BufferedReader(new InputStreamReader(stream)); + String line; + while ((line = in.readLine()) != null) { + stdout.append(line); + } + return stdout; + } + + public static class Process { + public final int exitCode; + public final String stdout; + public final String stderr; + + public Process(int exitCode, String stdout, String stderr) { + this.exitCode = exitCode; + this.stdout = stdout; + this.stderr = stderr; + } + } +} From edb0c7e03865e36d96684291d0d9b9c2d1ed71c8 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 15:18:29 -0300 Subject: [PATCH 15/24] Add CircleCI config --- circle.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 circle.yml diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..c7dd860 --- /dev/null +++ b/circle.yml @@ -0,0 +1,36 @@ +machine: + services: + - docker + +dependencies: + override: + - > + docker run + --env CIRCLE_BRANCH + --env CIRCLE_PROJECT_REPONAME + --env CIRCLE_TOKEN + --env GCR_JSON_KEY + --volume /var/run/docker.sock:/var/run/docker.sock + codeclimate/patrick pull || true + - make image + +test: + override: + - make test + +deployment: + registry: + branch: /master|channel\/[\w-]+/ + owner: codeclimate + commands: + - > + docker run + --env CIRCLE_BUILD_NUM + --env CIRCLE_PROJECT_REPONAME + --env GCR_JSON_KEY + --volume /var/run/docker.sock:/var/run/docker.sock + codeclimate/patrick push gcr + +notify: + webhooks: + - url: https://cc-slack-proxy.herokuapp.com/circle From 27cec4a52b4ad1946f50a18c31d7cd0625d46255 Mon Sep 17 00:00:00 2001 From: Filipe Esperandio Date: Wed, 4 Oct 2017 15:42:50 -0300 Subject: [PATCH 16/24] Remove files for restructure --- .gitignore | 30 -- .travis.yml | 26 -- Dockerfile | 40 -- LICENSE.txt | 165 -------- NOTICE.txt | 6 - README.md | 18 - appveyor.ps1 | 155 ------- appveyor.yml | 21 - assembly.xml | 46 -- circle.yml | 32 -- cix.sh | 21 - it/.gitignore | 1 - it/pom.xml | 83 ---- it/projects/java-no-issues/src/test/Java.txt | 1 - it/projects/java-sample/src/basic/Hello.java | 9 - it/projects/java-sample/src/basic/World.java | 8 - .../multi-language/src/main/java/Hello.java | 2 - .../multi-language/src/main/js/Hello.js | 3 - it/projects/no-files/placeholder.txt | 0 .../it/sonarlint/cli/ConnectedModeTest.java | 103 ----- .../java/it/sonarlint/cli/LanguageTest.java | 105 ----- .../java/it/sonarlint/cli/SonarlintTest.java | 81 ---- .../sonarlint/cli/tools/CommandExecutor.java | 115 ----- .../it/sonarlint/cli/tools/SonarlintCli.java | 136 ------ .../cli/tools/SonarlintInstaller.java | 128 ------ it/src/test/resources/java-sonarlint.xml | 20 - misc/symlink-tester.sh | 59 --- pom.xml | 241 ----------- src/main/assembly/bin/sonarlint | 66 --- src/main/assembly/bin/sonarlint.bat | 98 ----- .../org/sonarlint/cli/InputFileFinder.java | 168 -------- src/main/java/org/sonarlint/cli/Main.java | 223 ---------- src/main/java/org/sonarlint/cli/Options.java | 199 --------- .../org/sonarlint/cli/SonarProperties.java | 35 -- src/main/java/org/sonarlint/cli/Stats.java | 60 --- .../cli/analysis/ConnectedSonarLint.java | 228 ---------- .../cli/analysis/DefaultLogOutput.java | 53 --- .../cli/analysis/IssueCollector.java | 39 -- .../org/sonarlint/cli/analysis/SonarLint.java | 75 ---- .../cli/analysis/SonarLintFactory.java | 166 -------- .../cli/analysis/StandaloneSonarLint.java | 65 --- .../sonarlint/cli/analysis/package-info.java | 23 - .../cli/config/ConfigurationReader.java | 102 ----- .../cli/config/GlobalConfiguration.java | 33 -- .../cli/config/ProjectConfiguration.java | 37 -- .../sonarlint/cli/config/SonarQubeServer.java | 48 --- .../sonarlint/cli/config/package-info.java | 23 - .../java/org/sonarlint/cli/package-info.java | 23 - .../sonarlint/cli/report/CategoryReport.java | 61 --- .../cli/report/CategoryReportComparator.java | 63 --- .../sonarlint/cli/report/ConsoleReport.java | 150 ------- .../org/sonarlint/cli/report/HtmlReport.java | 159 ------- .../sonarlint/cli/report/IssueCategory.java | 86 ---- .../sonarlint/cli/report/IssueVariation.java | 100 ----- .../sonarlint/cli/report/IssuesReport.java | 263 ------------ .../org/sonarlint/cli/report/JsonReport.java | 106 ----- .../sonarlint/cli/report/ReportFactory.java | 75 ---- .../sonarlint/cli/report/ReportSummary.java | 82 ---- .../org/sonarlint/cli/report/Reporter.java | 32 -- .../sonarlint/cli/report/ResourceReport.java | 136 ------ .../org/sonarlint/cli/report/RichIssue.java | 35 -- .../org/sonarlint/cli/report/Severity.java | 51 --- .../sonarlint/cli/report/package-info.java | 23 - .../cli/report/source/CharactersReader.java | 67 --- .../report/source/DecorationDataHolder.java | 83 ---- .../report/source/HtmlSourceDecorator.java | 44 -- .../cli/report/source/HtmlTextDecorator.java | 133 ------ .../cli/report/source/OpeningHtmlTag.java | 40 -- .../cli/report/source/package-info.java | 23 - .../org/sonarlint/cli/util/HtmlEntities.java | 225 ---------- .../java/org/sonarlint/cli/util/Logger.java | 98 ----- .../org/sonarlint/cli/util/MutableInt.java | 61 --- .../java/org/sonarlint/cli/util/System2.java | 117 ----- .../org/sonarlint/cli/util/SystemInfo.java | 79 ---- .../java/org/sonarlint/cli/util/Util.java | 49 --- .../org/sonarlint/cli/util/package-info.java | 23 - .../sonarlint/cli/report/sonarlintreport.ftl | 349 --------------- .../cli/report/sonarlintreport_files/DIR.png | Bin 390 -> 0 bytes .../cli/report/sonarlintreport_files/FIL.png | Bin 416 -> 0 bytes .../cli/report/sonarlintreport_files/PRJ.png | Bin 575 -> 0 bytes .../report/sonarlintreport_files/favicon.ico | Bin 5430 -> 0 bytes .../sonarlintreport_files/jquery.min.js | 6 - .../cli/report/sonarlintreport_files/rule.css | 64 --- .../report/sonarlintreport_files/sep12.png | Bin 118 -> 0 bytes .../report/sonarlintreport_files/sonar.css | 400 ------------------ .../report/sonarlintreport_files/sonar.eot | Bin 6468 -> 0 bytes .../report/sonarlintreport_files/sonar.svg | 33 -- .../report/sonarlintreport_files/sonar.ttf | Bin 6312 -> 0 bytes .../report/sonarlintreport_files/sonar.woff | Bin 6904 -> 0 bytes .../sonarlintreport_files/sonarlint.png | Bin 1584 -> 0 bytes .../sonarlint/cli/InputFileFinderTest.java | 228 ---------- src/test/java/org/sonarlint/cli/MainTest.java | 222 ---------- .../java/org/sonarlint/cli/OptionsTest.java | 146 ------- .../java/org/sonarlint/cli/StatsTest.java | 60 --- .../java/org/sonarlint/cli/TestUtils.java | 40 -- .../cli/analysis/ConnectedSonarLintTest.java | 367 ---------------- .../cli/analysis/IssueCollectorTest.java | 39 -- .../cli/analysis/SonarLintFactoryTest.java | 215 ---------- .../cli/analysis/StandaloneSonarLintTest.java | 98 ----- .../cli/config/ConfigurationReaderTest.java | 160 ------- .../cli/report/CategoryReportTest.java | 48 --- .../cli/report/ConsoleReportTest.java | 148 ------- .../sonarlint/cli/report/HtmlReportTest.java | 109 ----- .../cli/report/IssueCategoryTest.java | 44 -- .../cli/report/IssueVariationTest.java | 68 --- .../cli/report/IssuesReportTest.java | 161 ------- .../cli/report/ReportFactoryTest.java | 63 --- .../cli/report/ReportSummaryTest.java | 79 ---- .../cli/report/ResourceReportTest.java | 127 ------ .../org/sonarlint/cli/util/LoggerTest.java | 113 ----- .../sonarlint/cli/util/MutableIntTest.java | 63 --- .../org/sonarlint/cli/util/System2Test.java | 46 -- .../sonarlint/cli/util/SystemInfoTest.java | 90 ---- .../java/org/sonarlint/cli/util/UtilTest.java | 34 -- .../cli/config/sonarlint_global.json | 10 - .../cli/config/sonarlint_project.json | 4 - third-party-licenses.sh | 4 - travis.sh | 13 - 118 files changed, 9534 deletions(-) delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 Dockerfile delete mode 100644 LICENSE.txt delete mode 100644 NOTICE.txt delete mode 100644 README.md delete mode 100644 appveyor.ps1 delete mode 100644 appveyor.yml delete mode 100644 assembly.xml delete mode 100644 circle.yml delete mode 100755 cix.sh delete mode 100644 it/.gitignore delete mode 100644 it/pom.xml delete mode 100644 it/projects/java-no-issues/src/test/Java.txt delete mode 100644 it/projects/java-sample/src/basic/Hello.java delete mode 100644 it/projects/java-sample/src/basic/World.java delete mode 100644 it/projects/multi-language/src/main/java/Hello.java delete mode 100644 it/projects/multi-language/src/main/js/Hello.js delete mode 100644 it/projects/no-files/placeholder.txt delete mode 100644 it/src/test/java/it/sonarlint/cli/ConnectedModeTest.java delete mode 100644 it/src/test/java/it/sonarlint/cli/LanguageTest.java delete mode 100644 it/src/test/java/it/sonarlint/cli/SonarlintTest.java delete mode 100644 it/src/test/java/it/sonarlint/cli/tools/CommandExecutor.java delete mode 100644 it/src/test/java/it/sonarlint/cli/tools/SonarlintCli.java delete mode 100644 it/src/test/java/it/sonarlint/cli/tools/SonarlintInstaller.java delete mode 100644 it/src/test/resources/java-sonarlint.xml delete mode 100755 misc/symlink-tester.sh delete mode 100644 pom.xml delete mode 100755 src/main/assembly/bin/sonarlint delete mode 100644 src/main/assembly/bin/sonarlint.bat delete mode 100644 src/main/java/org/sonarlint/cli/InputFileFinder.java delete mode 100644 src/main/java/org/sonarlint/cli/Main.java delete mode 100644 src/main/java/org/sonarlint/cli/Options.java delete mode 100644 src/main/java/org/sonarlint/cli/SonarProperties.java delete mode 100644 src/main/java/org/sonarlint/cli/Stats.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/ConnectedSonarLint.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/DefaultLogOutput.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/IssueCollector.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/SonarLint.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/SonarLintFactory.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/StandaloneSonarLint.java delete mode 100644 src/main/java/org/sonarlint/cli/analysis/package-info.java delete mode 100644 src/main/java/org/sonarlint/cli/config/ConfigurationReader.java delete mode 100644 src/main/java/org/sonarlint/cli/config/GlobalConfiguration.java delete mode 100644 src/main/java/org/sonarlint/cli/config/ProjectConfiguration.java delete mode 100644 src/main/java/org/sonarlint/cli/config/SonarQubeServer.java delete mode 100644 src/main/java/org/sonarlint/cli/config/package-info.java delete mode 100644 src/main/java/org/sonarlint/cli/package-info.java delete mode 100644 src/main/java/org/sonarlint/cli/report/CategoryReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/CategoryReportComparator.java delete mode 100644 src/main/java/org/sonarlint/cli/report/ConsoleReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/HtmlReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/IssueCategory.java delete mode 100644 src/main/java/org/sonarlint/cli/report/IssueVariation.java delete mode 100644 src/main/java/org/sonarlint/cli/report/IssuesReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/JsonReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/ReportFactory.java delete mode 100644 src/main/java/org/sonarlint/cli/report/ReportSummary.java delete mode 100644 src/main/java/org/sonarlint/cli/report/Reporter.java delete mode 100644 src/main/java/org/sonarlint/cli/report/ResourceReport.java delete mode 100644 src/main/java/org/sonarlint/cli/report/RichIssue.java delete mode 100644 src/main/java/org/sonarlint/cli/report/Severity.java delete mode 100644 src/main/java/org/sonarlint/cli/report/package-info.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/CharactersReader.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/DecorationDataHolder.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/HtmlSourceDecorator.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/HtmlTextDecorator.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/OpeningHtmlTag.java delete mode 100644 src/main/java/org/sonarlint/cli/report/source/package-info.java delete mode 100644 src/main/java/org/sonarlint/cli/util/HtmlEntities.java delete mode 100644 src/main/java/org/sonarlint/cli/util/Logger.java delete mode 100644 src/main/java/org/sonarlint/cli/util/MutableInt.java delete mode 100644 src/main/java/org/sonarlint/cli/util/System2.java delete mode 100644 src/main/java/org/sonarlint/cli/util/SystemInfo.java delete mode 100644 src/main/java/org/sonarlint/cli/util/Util.java delete mode 100644 src/main/java/org/sonarlint/cli/util/package-info.java delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport.ftl delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/DIR.png delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/FIL.png delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/PRJ.png delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/favicon.ico delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/jquery.min.js delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/rule.css delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sep12.png delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.css delete mode 100755 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.eot delete mode 100755 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.svg delete mode 100755 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.ttf delete mode 100755 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.woff delete mode 100644 src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonarlint.png delete mode 100644 src/test/java/org/sonarlint/cli/InputFileFinderTest.java delete mode 100644 src/test/java/org/sonarlint/cli/MainTest.java delete mode 100644 src/test/java/org/sonarlint/cli/OptionsTest.java delete mode 100644 src/test/java/org/sonarlint/cli/StatsTest.java delete mode 100644 src/test/java/org/sonarlint/cli/TestUtils.java delete mode 100644 src/test/java/org/sonarlint/cli/analysis/ConnectedSonarLintTest.java delete mode 100644 src/test/java/org/sonarlint/cli/analysis/IssueCollectorTest.java delete mode 100644 src/test/java/org/sonarlint/cli/analysis/SonarLintFactoryTest.java delete mode 100644 src/test/java/org/sonarlint/cli/analysis/StandaloneSonarLintTest.java delete mode 100644 src/test/java/org/sonarlint/cli/config/ConfigurationReaderTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/CategoryReportTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/ConsoleReportTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/HtmlReportTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/IssueCategoryTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/IssueVariationTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/IssuesReportTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/ReportFactoryTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/ReportSummaryTest.java delete mode 100644 src/test/java/org/sonarlint/cli/report/ResourceReportTest.java delete mode 100644 src/test/java/org/sonarlint/cli/util/LoggerTest.java delete mode 100644 src/test/java/org/sonarlint/cli/util/MutableIntTest.java delete mode 100644 src/test/java/org/sonarlint/cli/util/System2Test.java delete mode 100644 src/test/java/org/sonarlint/cli/util/SystemInfoTest.java delete mode 100644 src/test/java/org/sonarlint/cli/util/UtilTest.java delete mode 100644 src/test/resources/org/sonarlint/cli/config/sonarlint_global.json delete mode 100644 src/test/resources/org/sonarlint/cli/config/sonarlint_project.json delete mode 100644 third-party-licenses.sh delete mode 100755 travis.sh diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ae31f48..0000000 --- a/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ - -# ---- Maven -target/ -dependency-reduced-pom.xml - -# ---- IntellijIDEA -*.iws -*.iml -*.ipr -.idea/ - -# ---- Eclipse -.classpath -.project -.settings - -# ---- Mac OS X -.DS_Store -Icon? -# Thumbnails -._* -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# ---- Windows -# Windows image file caches -Thumbs.db -# Folder config file -Desktop.ini diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5902a3f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: java -sudo: false - -jdk: - - oraclejdk8 - -install: true -script: ./travis.sh - -cache: - directories: - - '$HOME/.m2/repository' - # for integration tests and analysis - - $HOME/.sonar - -notifications: - email: false - webhooks: - - secure: "LOtncSv54lCHHhLDRJ7tmVqBGWKeEvJNWXRu5oqVDVocJXy65IiaYU5OlfWmc/wn4iQC6dT3DEV4nF3wBdaIFioIp1CLO3ECo2w6LilQ1wra9Kgj47RazbcSkMrxJkz7wnn504JXok0pvX2/r9UCzJEi9D98jKQDCZ3tNw97YisiWevrhd9ExKG5tmlZea7r+AWdTpZ0EOTDOy95P+ZwPjEsArOXtkypK2DI1Bg5FDzU3xUo6CBRtICE3x5VdCmP2IdyK7Ll7ijX0YbkCrU8/BP00URmCWPNP2VmSBFpT/wXVmhjEYnHEKh21tJfMMv32U4z4ORvDlwlzZVpG4R0md3lR5Wnp5bLTqVkhkLAwgrPjNb9KIiVAV1wDMEy8xKpLHj8GXEcU/qZKi2rDxAj3Zv6ZV177QBZDRsWg5tkO8xxqSWVe9AoXhb6nHmYlFsu+dzJ/UgWZoc2s/3zrw3Kj8YwOSN0qmjDKdEE35TbGgQF/P56Vb5LooyEdK2g4RngiIyqF4OTX1AdSx5cgKbj5vDwGYLoLC0VclGpCPJDc6Vt/oDyAx+RyQOlvvgb8vaGXiIh1azE8ArDFqOb0x8vdIVCsCLnI4w+dcHOdqjVA2bOM0/eWadbRacRgP1DTGSCKfn4eUyyJPzmKicSDe4hkCm2xhhvbu5f/5AX0d0QVZs=" - -addons: - apt: - packages: - # upgrade java 8 as the default version 1.8.0_31 prevents from compiling sources - # https://github.com/travis-ci/travis-ci/issues/4042 - - oracle-java8-installer diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e66c145..0000000 --- a/Dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -FROM maven:3.3.9-jdk-8-alpine - -MAINTAINER Code Climate - -# Create user and app directory -RUN adduser -u 9000 -D app -COPY . /usr/src/app -RUN chown -R app:app /usr/src/app - -# Package the app with Maven -WORKDIR /usr/src/app -RUN mvn package - -# Unzip the packaged app -RUN mkdir /usr/src/app/dest -RUN unzip /usr/src/app/target/sonarlint-cli-*.zip \ - -d /usr/src/app/dest -RUN cp -R /usr/src/app/dest/sonarlint-cli-*/* \ - /usr/src/app/dest - -# Specify the /code volume -# as needed by CC -VOLUME /code - -# Create a writeable directory for the code -RUN mkdir -p /code-read-write -RUN chown -R app:app /code-read-write -RUN chmod -R 777 /code-read-write - -# Increase Java memory limits -ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" - -# Switch to app user, copy code to writable -# directory, and run the engine -USER app -ENTRYPOINT [] -WORKDIR /code-read-write -CMD cp -R /code/* . && \ - /usr/src/app/dest/bin/sonarlint \ - --src 'src/main/**/*.java' diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index b2966ba..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/NOTICE.txt b/NOTICE.txt deleted file mode 100644 index 9c080ab..0000000 --- a/NOTICE.txt +++ /dev/null @@ -1,6 +0,0 @@ -SonarLint CLI -Copyright (C) 2016-2017 SonarSource SA -mailto:info AT sonarsource DOT com - -This product includes software developed at -SonarSource (http://www.sonarsource.com/). \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 509a33b..0000000 --- a/README.md +++ /dev/null @@ -1,18 +0,0 @@ -SonarLint CLI [![Build Status](https://travis-ci.org/SonarSource/sonarlint-cli.svg?branch=master)](https://travis-ci.org/SonarSource/sonarlint-cli) -========================= - -Documentation: - -http://www.sonarlint.org/commandline - -http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner - -Issue Tracker: - -http://jira.sonarsource.com/browse/SLCLI - -### License - -Copyright 2016-2017 SonarSource. - -Licensed under the [GNU Lesser General Public License, Version 3.0](http://www.gnu.org/licenses/lgpl.txt) \ No newline at end of file diff --git a/appveyor.ps1 b/appveyor.ps1 deleted file mode 100644 index 4b1dd17..0000000 --- a/appveyor.ps1 +++ /dev/null @@ -1,155 +0,0 @@ -$ErrorActionPreference = "Stop" - -function FetchAndUnzip -{ - param ([string]$Url, [string]$Out) - - $tmp = [System.IO.Path]::GetTempFileName() - [System.Reflection.Assembly]::LoadWithPartialName('System.Net.Http') | Out-Null - $client = (New-Object System.Net.Http.HttpClient) - try - { - if (-not([string]::IsNullOrEmpty($env:GITHUB_TOKEN))) - { - $credentials = [string]::Format([System.Globalization.CultureInfo]::InvariantCulture, "{0}:", $env:GITHUB_TOKEN); - $credentials = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credentials)); - $client.DefaultRequestHeaders.Authorization = (New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Basic", $credentials)); - } - $contents = $client.GetByteArrayAsync($url).Result; - [System.IO.File]::WriteAllBytes($tmp, $contents); - } - finally - { - $client.Dispose() - } - - if (-not(Test-Path $Out)) - { - mkdir $Out | Out-Null - } - [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null - [System.IO.Compression.ZipFile]::ExtractToDirectory($tmp, $Out) -} - -function InstallAppveyorTools -{ - $travisUtilsVersion = "16" - $localPath = "$env:USERPROFILE\.local" - $travisUtilsPath = "$localPath\travis-utils-$travisUtilsVersion" - if (Test-Path $travisUtilsPath) - { - echo "Reusing the Travis Utils version $travisUtilsVersion already downloaded under $travisUtilsPath" - } - else - { - $url = "https://github.com/SonarSource/travis-utils/archive/v$travisUtilsVersion.zip" - echo "Downloading Travis Utils version $travisUtilsVersion from $url into $localPath" - FetchAndUnzip $url $localPath - } - - $mavenLocalRepository = "$env:USERPROFILE\.m2\repository" - if (-not(Test-Path $mavenLocalRepository)) - { - mkdir $mavenLocalRepository | Out-Null - } - echo "Installating Travis Utils closed source Maven projects into $mavenLocalRepository" - Copy-Item "$travisUtilsPath\m2repo\*" $mavenLocalRepository -Force -Recurse - - $env:ORCHESTRATOR_CONFIG_URL = "" - $env:TRAVIS = "ORCH-332" -} - -function Build -{ - param ([string]$Project, [string]$Sha1) - - $msg = "Fetch [" + $Project + ":" + $Sha1 + "]" - echo $msg - - $url = "https://github.com/$Project/archive/$Sha1.zip" - $tmp = "c:\snapshot" - if (Test-Path $tmp) - { - Cmd /C "rmdir /S /Q $tmp" - } - - FetchAndUnzip $url $tmp - - $msg = "Build [" + $Project + ":" + $Sha1 + "]" - echo $msg - - pushd $tmp\* - try - { - mvn install "--batch-mode" "-DskipTests" "-Pdev" - CheckLastExitCode - } - finally - { - popd - } -} - -function BuildSnapshot -{ - param ([string]$Project) - - echo "Fetch and build latest green snapshot of [$Project]" - - $lastGreenSha1 = (new-object Net.WebClient).DownloadString("http://sonarsource-979.appspot.com/$Project/latestGreen") - - Build $Project $lastGreenSha1 -} - -function CheckLastExitCode -{ - param ([int[]]$SuccessCodes = @(0)) - - if ($SuccessCodes -notcontains $LastExitCode) - { - $msg = @" -EXE RETURNED EXIT CODE $LastExitCode -CALLSTACK:$(Get-PSCallStack | Out-String) -"@ - throw $msg - } -} - -switch ($env:RUN) -{ - "ci" - { - mvn verify "--batch-mode" "-B" "-e" "-V" - CheckLastExitCode - } - - "it" - { - InstallAppveyorTools - BuildSnapshot "SonarSource/orchestrator" - - mvn install "--batch-mode" "-Dsource.skip=true" "-Dmaven.test.skip=true" - CheckLastExitCode - - if ($env:SQ_VERSION -eq "DEV") - { - BuildSnapshot "SonarSource/sonarqube" - } - - pushd it - try - { - mvn install "--batch-mode" "-DsonarRunner.version=""2.5-SNAPSHOT""" "-Dsonar.runtimeVersion=""$env:SQ_VERSION""" "-Dmaven.test.redirectTestOutputToFile=false" - CheckLastExitCode - } - finally - { - popd - } - } - - default - { - throw "Unexpected RUN mode: $env:RUN" - } -} diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index a79be7b..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: 1.0.{build} - -branches: - only: - - master - -cache: - - C:\Users\appveyor\.m2 -> **\pom.xml - -install: - - set MAVEN_VERSION=3.2.5 - - choco install maven -version %MAVEN_VERSION% - - set PATH=%PATH%;C:\bin\apache-maven-%MAVEN_VERSION%\bin - - set JAVA_HOME=C:\Program Files\Java\jdk1.7.0 - -environment: - matrix: - - RUN: ci - -build_script: - - ps: ./appveyor.ps1 diff --git a/assembly.xml b/assembly.xml deleted file mode 100644 index 2754f89..0000000 --- a/assembly.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - bin - - zip - - true - - - lib - true - true - - org.freemarker:freemarker - org.sonarsource.sonarlint.core:sonarlint-core - - - - - - src/main/assembly/bin - bin - - sonarlint.bat - - dos - true - - - src/main/assembly/bin - bin - - sonarlint - - unix - 0755 - true - - - ${project.build.directory}/plugins - plugins - - - diff --git a/circle.yml b/circle.yml deleted file mode 100644 index a231d4a..0000000 --- a/circle.yml +++ /dev/null @@ -1,32 +0,0 @@ -machine: - services: - - docker - -dependencies: - override: - - > - docker run - --env CIRCLE_BRANCH - --env CIRCLE_PROJECT_REPONAME - --env CIRCLE_TOKEN - --env GCR_JSON_KEY - --volume /var/run/docker.sock:/var/run/docker.sock - codeclimate/patrick pull || true - - docker build --rm --tag codeclimate/codeclimate-checks . - -deployment: - registry: - branch: /master|channel\/[\w-]+/ - owner: codeclimate - commands: - - > - docker run - --env CIRCLE_BUILD_NUM - --env CIRCLE_PROJECT_REPONAME - --env GCR_JSON_KEY - --volume /var/run/docker.sock:/var/run/docker.sock - codeclimate/patrick push gcr - -notify: - webhooks: - - url: https://cc-slack-proxy.herokuapp.com/circle diff --git a/cix.sh b/cix.sh deleted file mode 100755 index a9627b9..0000000 --- a/cix.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -set -euo pipefail - -CURRENT_VERSION=`mvn help:evaluate -Dexpression="project.version" | grep -v '^\[\|Download\w\+\:'` - -if [[ $CURRENT_VERSION =~ "-SNAPSHOT" ]]; then - echo "Running locally" -else - echo "Running for $CI_BUILD_NUMBER" - #deploy the version built by travis - mkdir -p target - cd target - curl --user $ARTIFACTORY_QA_READER_USERNAME:$ARTIFACTORY_QA_READER_PASSWORD -sSLO https://repox.sonarsource.com/sonarsource-public-qa/org/sonarsource/sonarlint/cli/sonarlint-cli/$CURRENT_VERSION/sonarlint-cli-$CURRENT_VERSION.zip - cd .. - mvn install:install-file -Dfile=target/sonarlint-cli-$CURRENT_VERSION.zip -DgroupId=org.sonarsource.sonarlint.cli \ - -DartifactId=sonarlint-cli -Dversion=$CURRENT_VERSION -Dpackaging=zip -fi - -# Run ITs -cd it -mvn test -Dsonarlint.version=$CURRENT_VERSION -Dsonar.runtimeVersion=LATEST_RELEASE -B -e -V diff --git a/it/.gitignore b/it/.gitignore deleted file mode 100644 index b83d222..0000000 --- a/it/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/it/pom.xml b/it/pom.xml deleted file mode 100644 index 31cdb63..0000000 --- a/it/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - 4.0.0 - - - org.sonarsource.parent - parent - 39 - - - - com.sonarsource.it - it-sonarlint-cli - 1.0-SNAPSHOT - SonarSource :: IT :: SonarLint CLI - 2016 - - - SonarSource - http://www.sonarsource.com - - - - 5.0 - -server - - - - - - junit - junit - 4.11 - - - org.apache.commons - commons-exec - 1.3 - - - org.apache.commons - commons-lang3 - 3.4 - - - net.lingala.zip4j - zip4j - 1.3.2 - - - commons-io - commons-io - 2.4 - - - org.slf4j - slf4j-api - 1.7.2 - - - org.sonarsource.orchestrator - sonar-orchestrator - 3.14.0.887 - - - ch.qos.logback - logback-classic - 1.0.13 - - - com.google.code.findbugs - jsr305 - 3.0.0 - - - org.assertj - assertj-core - 2.1.0 - - - - diff --git a/it/projects/java-no-issues/src/test/Java.txt b/it/projects/java-no-issues/src/test/Java.txt deleted file mode 100644 index a2c3f3f..0000000 --- a/it/projects/java-no-issues/src/test/Java.txt +++ /dev/null @@ -1 +0,0 @@ -No source code diff --git a/it/projects/java-sample/src/basic/Hello.java b/it/projects/java-sample/src/basic/Hello.java deleted file mode 100644 index b9db5a0..0000000 --- a/it/projects/java-sample/src/basic/Hello.java +++ /dev/null @@ -1,9 +0,0 @@ -package basic; - -public class Hello { - - public void hello() { - int i=356; - if (true) i=5658; - } -} diff --git a/it/projects/java-sample/src/basic/World.java b/it/projects/java-sample/src/basic/World.java deleted file mode 100644 index c65d91c..0000000 --- a/it/projects/java-sample/src/basic/World.java +++ /dev/null @@ -1,8 +0,0 @@ -package basic; - -public final class World { - - public void world() { - System.out.println("hello world"); - } -} diff --git a/it/projects/multi-language/src/main/java/Hello.java b/it/projects/multi-language/src/main/java/Hello.java deleted file mode 100644 index 8a94806..0000000 --- a/it/projects/multi-language/src/main/java/Hello.java +++ /dev/null @@ -1,2 +0,0 @@ -public class Hello { -} diff --git a/it/projects/multi-language/src/main/js/Hello.js b/it/projects/multi-language/src/main/js/Hello.js deleted file mode 100644 index 2096104..0000000 --- a/it/projects/multi-language/src/main/js/Hello.js +++ /dev/null @@ -1,3 +0,0 @@ -function hello() { - alert("Hello World"); -} diff --git a/it/projects/no-files/placeholder.txt b/it/projects/no-files/placeholder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/it/src/test/java/it/sonarlint/cli/ConnectedModeTest.java b/it/src/test/java/it/sonarlint/cli/ConnectedModeTest.java deleted file mode 100644 index 66fdb1c..0000000 --- a/it/src/test/java/it/sonarlint/cli/ConnectedModeTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.locator.FileLocation; -import it.sonarlint.cli.tools.SonarlintCli; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ConnectedModeTest { - private static final String PROJECT_KEY_JAVA = "sample-java"; - - @ClassRule - public static SonarlintCli sonarlint = new SonarlintCli(); - - @ClassRule - public static Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() - .setOrchestratorProperty("javaVersion", "LATEST_RELEASE") - .addPlugin("java") - .restoreProfileAtStartup(FileLocation.ofClasspath("/java-sonarlint.xml")) - .build(); - - @ClassRule - public static TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @BeforeClass - public static void prepare() throws Exception { - ORCHESTRATOR.getServer().provisionProject(PROJECT_KEY_JAVA, "Sample Java"); - ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT_KEY_JAVA, "java", "SonarLint IT Java"); - } - - @Before - public void setUp() throws IOException { - createGlobalConfig(ORCHESTRATOR.getServer().getUrl()); - sonarlint.install(); - } - - @Test - public void testSimpleJava() throws IOException { - Path projectRoot = sonarlint.deployProject("java-sample"); - - createProjectConfig(projectRoot, PROJECT_KEY_JAVA); - - int code = sonarlint.run(projectRoot, "-u"); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("No storage for server"); - assertThat(sonarlint.getOut()).contains("Updating binding"); - assertThat(sonarlint.getOut()).contains("Using storage for server"); - - assertThat(sonarlint.getOut()).contains("1 issue"); - assertThat(sonarlint.getOut()).contains("1 major"); - assertThat(sonarlint.getOut()).contains("3 files analyzed"); - } - - private void createProjectConfig(Path projectRoot, String projectKey) throws IOException { - Path configFile = projectRoot.resolve("sonarlint.json"); - String json = "{serverId=\"local\", projectKey=" + projectKey + "}"; - Files.write(configFile, json.getBytes(StandardCharsets.UTF_8)); - } - - private void createGlobalConfig(String serverUrl) throws IOException { - Path configDir = temp.getRoot().toPath().resolve(".sonarlint").resolve("conf"); - Files.createDirectories(configDir); - Path configFile = configDir.resolve("global.json"); - String json = "{servers=[{id=\"local\",url=\"" + serverUrl + "\"}]}"; - Files.write(configFile, json.getBytes(StandardCharsets.UTF_8)); - sonarlint.addEnv("SONARLINT_OPTS", "-Duser.home=" + temp.getRoot().toPath().toAbsolutePath().toString()); - } - -} diff --git a/it/src/test/java/it/sonarlint/cli/LanguageTest.java b/it/src/test/java/it/sonarlint/cli/LanguageTest.java deleted file mode 100644 index c2ec325..0000000 --- a/it/src/test/java/it/sonarlint/cli/LanguageTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli; - -import it.sonarlint.cli.tools.SonarlintCli; -import java.io.IOException; -import java.nio.file.Path; -import org.apache.commons.io.FileUtils; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LanguageTest { - @ClassRule - public static SonarlintCli sonarlint = new SonarlintCli(); - - @Before - public void setUp() { - sonarlint.install(); - } - - @Test - public void testSimpleJava() { - int code = sonarlint.deployAndRunProject("java-sample"); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("6 issues"); - assertThat(sonarlint.getOut()).contains("5 major"); - assertThat(sonarlint.getOut()).contains("1 minor"); - assertThat(sonarlint.getOut()).contains("2 files analyzed"); - } - - @Test - public void testRunTwice() throws IOException { - Path project = sonarlint.deployProject("java-sample"); - int code = sonarlint.run(project); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("6 issues"); - assertThat(sonarlint.getOut()).contains("5 major"); - assertThat(sonarlint.getOut()).contains("1 minor"); - assertThat(sonarlint.getOut()).contains("2 files analyzed"); - - FileUtils.deleteDirectory(project.resolve(".sonarlint").toFile()); - code = sonarlint.run(project); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("6 issues"); - assertThat(sonarlint.getOut()).contains("5 major"); - assertThat(sonarlint.getOut()).contains("1 minor"); - assertThat(sonarlint.getOut()).contains("2 files analyzed"); - } - - @Test - public void testMultiLanguage() { - int code = sonarlint.deployAndRunProject("multi-language", "-X"); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("src/main/js/Hello.js' is detected to be 'js'"); - assertThat(sonarlint.getOut()).contains("src/main/java/Hello.java' is detected to be 'java'"); - - assertThat(sonarlint.getOut()).contains("3 issues"); - assertThat(sonarlint.getOut()).contains("3 minor"); - - // 1 of each lang - assertThat(sonarlint.getOut()).contains("2 files analyzed"); - } - - @Test - public void testNoIssues() { - int code = sonarlint.deployAndRunProject("java-no-issues"); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("No issues to display"); - assertThat(sonarlint.getOut()).contains("1 file analyzed"); - } - - @Test - public void testNoFiles() { - int code = sonarlint.deployAndRunProject("no-files", "-X", "--src", "src/**"); - assertThat(code).isEqualTo(0); - - assertThat(sonarlint.getOut()).contains("No files to analyze"); - } - -} diff --git a/it/src/test/java/it/sonarlint/cli/SonarlintTest.java b/it/src/test/java/it/sonarlint/cli/SonarlintTest.java deleted file mode 100644 index db42049..0000000 --- a/it/src/test/java/it/sonarlint/cli/SonarlintTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli; - -import it.sonarlint.cli.tools.SonarlintCli; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SonarlintTest { - @ClassRule - public static SonarlintCli sonarlint = new SonarlintCli(); - - @Before - public void setUp() { - sonarlint.install(); - } - - @Test - public void testHelp() { - int code = sonarlint.run(Paths.get(""), "-h"); - assertThat(sonarlint.getOut()).contains("usage: sonarlint"); - assertThat(code).isEqualTo(0); - } - - @Test - public void testVersion() { - int code = sonarlint.run(Paths.get(""), "-v"); - String version = System.getProperty("sonarlint.version"); - assertThat(sonarlint.getOut()).contains(version); - assertThat(code).isEqualTo(0); - } - - @Test - public void testInvalidArg() { - int code = sonarlint.run(Paths.get(""), "-q"); - assertThat(sonarlint.getErr()).contains("Error parsing arguments"); - assertThat(sonarlint.getOut()).contains("usage: sonarlint"); - assertThat(code).isEqualTo(1); - } - - @Test - public void testPluginsInstalled() throws IOException { - Path installation = sonarlint.getSonarlintInstallation(); - Path plugins = installation.resolve("plugins"); - assertThat(Files.isDirectory(plugins)).isTrue(); - assertThat(Files.newDirectoryStream(plugins)).isNotEmpty(); - } - - @Test - public void testNoFilesToAnalyse() throws IOException { - Path empty = Files.createTempDirectory("empty"); - int code = sonarlint.run(empty); - assertThat(code).isEqualTo(0); - assertThat(sonarlint.getOut()).contains("WARN: No files to analyze"); - } -} diff --git a/it/src/test/java/it/sonarlint/cli/tools/CommandExecutor.java b/it/src/test/java/it/sonarlint/cli/tools/CommandExecutor.java deleted file mode 100644 index 4001fb6..0000000 --- a/it/src/test/java/it/sonarlint/cli/tools/CommandExecutor.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli.tools; - -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.ExecuteStreamHandler; -import org.apache.commons.exec.ExecuteWatchdog; -import org.apache.commons.exec.PumpStreamHandler; -import org.apache.commons.io.output.TeeOutputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class CommandExecutor { - private static final Logger LOG = LoggerFactory.getLogger(CommandExecutor.class); - private static final int TIMEOUT = 60_000; - private Path file; - - private ByteArrayOutputStream out; - private ByteArrayOutputStream err; - private OutputStream in; - - public CommandExecutor(Path file) { - this.file = file; - } - - public int execute(String[] args) throws IOException { - return execute(args, null, Collections.emptyMap()); - } - - public int execute(String[] args, @Nullable Path workingDir, Map addEnv) throws IOException { - if (!Files.isExecutable(file)) { - Set perms = new HashSet(); - perms.add(PosixFilePermission.OWNER_READ); - perms.add(PosixFilePermission.OWNER_EXECUTE); - Files.setPosixFilePermissions(file, perms); - } - - ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT); - CommandLine cmd = new CommandLine(file.toFile()); - cmd.addArguments(args); - DefaultExecutor exec = new DefaultExecutor(); - exec.setWatchdog(watchdog); - exec.setStreamHandler(createStreamHandler()); - exec.setExitValues(null); - if (workingDir != null) { - exec.setWorkingDirectory(workingDir.toFile()); - } - in.close(); - LOG.info("Executing: {}", cmd.toString()); - Map env = new HashMap<>(System.getenv()); - env.putAll(addEnv); - return exec.execute(cmd, env); - } - - public String getStdOut() { - return getLogs(out); - } - - public String getStdErr() { - return getLogs(err); - } - - private static String getLogs(ByteArrayOutputStream stream) { - return new String(stream.toByteArray(), Charset.defaultCharset()); - } - - private ExecuteStreamHandler createStreamHandler() throws IOException { - out = new ByteArrayOutputStream(); - err = new ByteArrayOutputStream(); - PipedOutputStream outPiped = new PipedOutputStream(); - InputStream inPiped = new PipedInputStream(outPiped); - in = outPiped; - - TeeOutputStream teeOut = new TeeOutputStream(out, System.out); - TeeOutputStream teeErr = new TeeOutputStream(err, System.err); - - return new PumpStreamHandler(teeOut, teeErr, inPiped); - } -} diff --git a/it/src/test/java/it/sonarlint/cli/tools/SonarlintCli.java b/it/src/test/java/it/sonarlint/cli/tools/SonarlintCli.java deleted file mode 100644 index 35384b6..0000000 --- a/it/src/test/java/it/sonarlint/cli/tools/SonarlintCli.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli.tools; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.io.FileUtils; -import org.junit.rules.ExternalResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SonarlintCli extends ExternalResource { - private static final Logger LOG = LoggerFactory.getLogger(SonarlintCli.class); - private Path script; - private Path installPath; - private Path project; - private CommandExecutor exec; - private Map env = new HashMap<>(); - - public void install() { - String version = System.getProperty("sonarlint.version"); - if (version == null) { - throw new IllegalStateException("No sonarlint-cli version specified. Use '-Dsonarlint.version'."); - } - install(version); - } - - public void install(String version) { - SonarlintInstaller installer = new SonarlintInstaller(); - this.script = installer.install(installPath, version); - } - - public void addEnv(String key, String value) { - env.put(key, value); - } - - public int run(Path workingDir, String... args) { - LOG.info("Running SonarLint CLI in '{}'", workingDir.toAbsolutePath()); - try { - exec = new CommandExecutor(script); - return exec.execute(args, workingDir.toAbsolutePath(), env); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public int deployAndRunProject(String location, String... args) { - LOG.info("Running SonarLint CLI on project '{}'", location); - try { - Path project = deployProject(location); - exec = new CommandExecutor(script); - return exec.execute(args, project, env); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public Path deployProject(String location) throws IOException { - Path originalLoc = Paths.get("projects").resolve(location); - String projectName = originalLoc.getFileName().toString(); - - if (!Files.isDirectory(originalLoc)) { - throw new IllegalArgumentException("Couldn't find project directory: " + originalLoc.toAbsolutePath().toString()); - } - - cleanProject(); - project = Files.createTempDirectory(projectName); - FileUtils.copyDirectory(originalLoc.toFile(), project.toFile()); - return project; - } - - private void cleanProject() { - if (project != null) { - FileUtils.deleteQuietly(project.toFile()); - project = null; - } - } - - protected void before() throws Throwable { - installPath = Files.createTempDirectory("sonarlint-cli"); - } - - protected void after() { - cleanProject(); - if (installPath != null) { - FileUtils.deleteQuietly(installPath.toFile()); - installPath = null; - } - } - - public String getOut() { - return exec.getStdOut(); - } - - public String[] getOutLines() { - return getOut().split(System.lineSeparator()); - } - - public Path getProject() { - return project; - } - - public Path getSonarlintInstallation() { - return script.getParent().getParent(); - } - - public String getErr() { - return exec.getStdErr(); - } - - public String[] getErrLines() { - return getErr().split(System.lineSeparator()); - } -} diff --git a/it/src/test/java/it/sonarlint/cli/tools/SonarlintInstaller.java b/it/src/test/java/it/sonarlint/cli/tools/SonarlintInstaller.java deleted file mode 100644 index 6a6ecc9..0000000 --- a/it/src/test/java/it/sonarlint/cli/tools/SonarlintInstaller.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarSource :: IT :: SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package it.sonarlint.cli.tools; - -import net.lingala.zip4j.core.ZipFile; -import org.apache.commons.lang3.SystemUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * Attempts to install a specific version of SonarLint CLI from the local maven repository. - * The location of the local maven repository can be passed with the environmental variable 'MAVEN_LOCAL_REPOSITORY'. - */ -public class SonarlintInstaller { - private static final String GROUP_ID = "org.sonarsource.sonarlint.cli"; - private static final String ARTIFACT_ID = "sonarlint-cli"; - private static final Logger LOG = LoggerFactory.getLogger(SonarlintInstaller.class); - - public Path install(Path installPath, String version) { - if (!isInstalled(installPath, version)) { - Path zipFile = locateZipInLocalMaven(version); - installZip(zipFile, installPath); - } - - return locateScript(version, installPath); - } - - private static Path locateScript(String version, Path installPath) { - String directoryName = "sonarlint-cli-" + version; - String fileName = SystemUtils.IS_OS_WINDOWS ? "sonarlint.bat" : "sonarlint"; - - Path script = installPath.resolve(directoryName).resolve("bin").resolve(fileName); - - if (!Files.exists(script)) { - throw new IllegalStateException("File does not exist: " + script); - } - return script; - } - - private boolean isInstalled(Path installPath, String version) { - String directoryName = "sonarlint-cli-" + version; - - Path sonarlint = installPath.resolve(directoryName); - - if (Files.isDirectory(sonarlint)) { - LOG.debug("SonarLint CLI {} already exists in {}", version, installPath); - return true; - } - return false; - } - - private void installZip(Path zipFilePath, Path toDir) { - try { - ZipFile zipFile = new ZipFile(zipFilePath.toFile()); - zipFile.extractAll(toDir.toString()); - } catch (Exception e) { - throw new IllegalStateException("Fail to unzip sonarlint cli to" + toDir, e); - } - } - - private Path locateZipInLocalMaven(String version) { - String fileName = "sonarlint-cli-" + version + ".zip"; - - LOG.info("Searching for SonarLint CLI {} in maven repositories", version); - - Path mvnRepo = getMavenLocalRepository(); - Path file = getMavenFilePath(mvnRepo, GROUP_ID, ARTIFACT_ID, version, fileName); - - if (!Files.exists(file)) { - throw new IllegalArgumentException("Couldn't find in local repo: sonarlint cli " + file.toString()); - } - return file; - } - - private static Path getMavenFilePath(Path mvnRepo, String groupId, String artifactId, String version, String fileName) { - Path p = mvnRepo; - String[] split = groupId.split("\\."); - - for (String s : split) { - p = p.resolve(s); - } - - p = p.resolve(artifactId); - p = p.resolve(version); - return p.resolve(fileName); - } - - private Path getMavenLocalRepository() { - if (System.getenv("MAVEN_LOCAL_REPOSITORY") != null) { - Path repo = Paths.get(System.getenv("MAVEN_LOCAL_REPOSITORY")); - if (!Files.isDirectory(repo)) { - throw new IllegalArgumentException("Maven local repository is not valid: " + System.getenv("MAVEN_LOCAL_REPOSITORY")); - } - return repo; - } - - String home = System.getProperty("user.home"); - Path repo = Paths.get(home).resolve(".m2").resolve("repository"); - - if (!Files.isDirectory(repo)) { - throw new IllegalArgumentException("Couldn't find maven repository. Please define MAVEN_LOCAL_REPOSITORY in the environment."); - } - - LOG.info("Using maven repository: {}", repo); - return repo; - } -} diff --git a/it/src/test/resources/java-sonarlint.xml b/it/src/test/resources/java-sonarlint.xml deleted file mode 100644 index 2644cac..0000000 --- a/it/src/test/resources/java-sonarlint.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - SonarLint IT Java - java - - - - squid - S106 - MAJOR - - - - squid - S2325 - MAJOR - - - - \ No newline at end of file diff --git a/misc/symlink-tester.sh b/misc/symlink-tester.sh deleted file mode 100755 index dd9bf87..0000000 --- a/misc/symlink-tester.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -usage() { - echo usage: $0 path/to/sonarlint - exit 1 -} - -test -f "$1" && test -x "$1" || usage - -sonarlint=$1 - -if type mktemp &>/dev/null; then - tempdir=$(mktemp -d) -else - tempdir=/tmp/"$(basename "$0")-$$" - mkdir -p "$tempdir" -fi - -cleanup() { - rm -fr "$tempdir" -} - -trap 'cleanup; exit 1' 1 2 3 15 - -abspath() { - (cd "$(dirname "$1")"; echo $PWD/"$(basename "$1")") -} - -verify() { - printf '%s -> ' "$1" - shift - "$@" &>/dev/null && echo ok || echo failed -} - -relpath_to_root() { - ( - cd "$1" - relpath=. - while test "$PWD" != /; do - cd .. - relpath=$relpath/.. - done - echo $relpath - ) -} - -ln -s "$(abspath "$sonarlint")" "$tempdir"/sonarlint -verify 'launch from abs symlink to abs path' "$tempdir"/sonarlint -h - -ln -s $(relpath_to_root "$tempdir")/"$(abspath "$sonarlint")" "$tempdir"/sonarlint-rel -verify 'symlink to rel path is valid' test -f "$tempdir"/sonarlint-rel -verify 'launch from abs symlink to rel path' "$tempdir"/sonarlint-rel -h - -mkdir "$tempdir/x" -ln -s ../sonarlint "$tempdir"/x/sonarlint -verify 'symlink to rel symlink is valid' test -f "$tempdir"/x/sonarlint -verify 'launch from abs symlink that is rel symlink to abs path' "$tempdir"/x/sonarlint -h - -cleanup diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 3b6911f..0000000 --- a/pom.xml +++ /dev/null @@ -1,241 +0,0 @@ - - 4.0.0 - - org.sonarsource.parent - parent - 39 - - - org.sonarsource.sonarlint.cli - sonarlint-cli - 2.2-SNAPSHOT - jar - SonarLint CLI - http://www.sonarlint.org - 2016 - - - SonarSource - http://www.sonarsource.com - - - - - GNU LGPL 3 - http://www.gnu.org/licenses/lgpl.txt - repo - - - - - scm:git:git@github.com:SonarSource/sonarlint-cli.git - scm:git:git@github.com:SonarSource/sonarlint-cli.git - https://github.com/SonarSource/sonarlint-cli - HEAD - - - - JIRA - https://jira.sonarsource.com/browse/SLCLI - - - - true - sonarlint-cli - 2.10.0.367 - 4.3.0.7717 - 2.18.0.3454 - 2.9.1.1705 - 1.6 - - ${project.groupId}:${project.artifactId}:zip - - - - - org.sonarsource.sonarlint.core - sonarlint-core - ${sonarlint.version} - - - org.sonarsource.sonarlint.core - sonarlint-client-api - ${sonarlint.version} - - - com.google.code.findbugs - jsr305 - 2.0.1 - provided - - - org.freemarker - freemarker - 2.3.25-incubating - - - - - junit - junit - 4.11 - test - - - org.mockito - mockito-all - 1.10.19 - test - - - org.assertj - assertj-core - 2.3.0 - test - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - false - true - org.sonarlint.cli.Main - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - true - - false - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy - package - - copy - - - - - org.sonarsource.java - sonar-java-plugin - ${sonar.java.version} - jar - false - ${project.build.directory}/plugins - - - org.sonarsource.javascript - sonar-javascript-plugin - ${sonar.javascript.version} - jar - false - ${project.build.directory}/plugins - - - org.sonarsource.php - sonar-php-plugin - ${sonar.php.version} - jar - false - ${project.build.directory}/plugins - - - org.sonarsource.python - sonar-python-plugin - ${sonar.python.version} - jar - false - ${project.build.directory}/plugins - - - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - sonarlint-cli-${project.version} - false - \ - - ${project.basedir}/assembly.xml - - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - enforce-distribution-size - - enforce - - verify - - - - 30000000 - 50000000 - - ${project.build.directory}/sonarlint-cli-${project.version}.zip - - - - - - - - - - diff --git a/src/main/assembly/bin/sonarlint b/src/main/assembly/bin/sonarlint deleted file mode 100755 index a8cc4e4..0000000 --- a/src/main/assembly/bin/sonarlint +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# SonarLint Startup Script for Unix -# -# Optional ENV vars: -# SONARLINT_OPTS - parameters passed to the Java VM when running SonarLint - -real_path() { - target=$1 - - ( - while true; do - cd "$(dirname "$target")" - target=$(basename "$target") - link=$(readlink "$target") - test "$link" || break - target=$link - done - - echo "$(pwd -P)/$target" - ) -} - -script_path="$0" - -if [ -h "$script_path" ]; then - # resolve symlinks - script_path=$(real_path "$script_path") -fi - -sonarlint_home=$(dirname "$script_path")/.. - -# make it fully qualified -sonarlint_home=$(cd "$sonarlint_home" && pwd -P) - -# check that the sonarlint_home has been correctly set -if [ ! -f "$sonarlint_home/lib/sonarlint-cli-${project.version}.jar" ] ; then - echo "fatal: detected installation directory is invalid: $sonarlint_home" - echo 'fatal: lib/sonarlint-cli-${project.version}.jar should exist relative from the installation directory' - exit 1 -fi - -if [ -n "$JAVA_HOME" ] -then - java_cmd="$JAVA_HOME/bin/java" -else - java_cmd="$(which java)" -fi - -jar_file="$sonarlint_home"/lib/sonarlint-cli-${project.version}.jar -project_home=$PWD - -#echo "Info: Using sonarlint-cli in $sonarlint_home" -#echo "Info: Using java at $java_cmd" -#echo "Info: Using classpath $jar_file" -#echo "Info: Using project $project_home" - -exec "$java_cmd" \ - -Djava.awt.headless=true \ - $SONARLINT_OPTS \ - -classpath "$jar_file" \ - -Dsonarlint.home="$sonarlint_home" \ - -Dproject.home="$project_home" \ - -Dorg.freemarker.loggerLibrary=none \ - org.sonarlint.cli.Main "$@" - diff --git a/src/main/assembly/bin/sonarlint.bat b/src/main/assembly/bin/sonarlint.bat deleted file mode 100644 index e704af2..0000000 --- a/src/main/assembly/bin/sonarlint.bat +++ /dev/null @@ -1,98 +0,0 @@ -@REM SonarLint Startup Script for Windows -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars: -@REM SONARLINT_HOME - location of SonarLint's installed home dir -@REM SONARLINT_OPTS - parameters passed to the Java VM when running SonarLint - -@echo off - -set ERROR_CODE=0 - -@REM set local scope for the variables with windows NT shell -@setlocal - -@REM ==== START VALIDATION ==== -@REM *** JAVA EXEC VALIDATION *** -if not "%JAVA_HOME%" == "" goto foundJavaHome - -for %%i in (java.exe) do set JAVA_EXEC=%%~$PATH:i - -if not "%JAVA_EXEC%" == "" ( - set JAVA_EXEC="%JAVA_EXEC%" - goto OkJava -) - -if not "%JAVA_EXEC%" == "" goto OkJava - -echo. -echo ERROR: JAVA_HOME not found in your environment, and no Java -echo executable present in the PATH. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation, or add "java.exe" to the PATH -echo. -goto error - -:foundJavaHome -if EXIST "%JAVA_HOME%\bin\java.exe" goto foundJavaExeFromJavaHome - -echo. -echo ERROR: JAVA_HOME exists but does not point to a valid Java home -echo folder. No "\bin\java.exe" file can be found there. -echo. -goto error - -:foundJavaExeFromJavaHome -set JAVA_EXEC="%JAVA_HOME%\bin\java.exe" - -@REM *** SONARLINT HOME VALIDATION *** -:OkJava -if NOT "%SONARLINT_HOME%"=="" goto cleanSonarLintHome -set SONARLINT_HOME=%~dp0.. -goto run - -:cleanSonarLintHome -@REM If the property has a trailing backslash, remove it -if "%SONARLINT_HOME:~-1%"=="\" set SONARLINT_HOME=%SONARLINT_HOME:~0,-1% - -@REM Check if the provided SONARLINT_HOME is a valid install dir -IF EXIST "%SONARLINT_HOME%\lib\sonarlint-cli-${project.version}.jar" goto run - -echo. -echo ERROR: SONARLINT_HOME exists but does not point to a valid install -echo directory: %SONARLINT_HOME% -echo. -goto error - - - -@REM ==== START RUN ==== -:run -echo %SONARLINT_HOME% - -set PROJECT_HOME=%CD% -if not "%SONARLINT_OPTS%"=="" set SONARLINT_OPTS="%SONARLINT_OPTS%" - -%JAVA_EXEC% -Djava.awt.headless=true %SONARLINT_OPTS% -cp "%SONARLINT_HOME%\lib\sonarlint-cli-${project.version}.jar" "-Dsonarlint.home=%SONARLINT_HOME%" "-Dproject.home=%PROJECT_HOME%" -Dorg.freemarker.loggerLibrary=none org.sonarlint.cli.Main %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -@REM ==== END EXECUTION ==== - -:end -@REM set local scope for the variables with windows NT shell -@endlocal & set ERROR_CODE=%ERROR_CODE% - -@REM see http://code-bear.com/bearlog/2007/06/01/getting-the-exit-code-from-a-batch-file-that-is-run-from-a-python-program/ -goto exit - -:returncode -exit /B %1 - -:exit -call :returncode %ERROR_CODE% diff --git a/src/main/java/org/sonarlint/cli/InputFileFinder.java b/src/main/java/org/sonarlint/cli/InputFileFinder.java deleted file mode 100644 index 67354d0..0000000 --- a/src/main/java/org/sonarlint/cli/InputFileFinder.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; - -public class InputFileFinder { - private static final String GLOB_PREFIX = "glob:"; - private static final Logger LOGGER = Logger.get(); - private final PathMatcher srcMatcher; - private final PathMatcher testsMatcher; - private final PathMatcher excludeMatcher; - private final Charset charset; - - private static PathMatcher acceptAll = p -> true; - private static PathMatcher refuseAll = p -> false; - - public InputFileFinder(@Nullable String srcGlobPattern, @Nullable String testsGlobPattern, @Nullable String excludeGlobPattern, Charset charset) { - this.charset = charset; - FileSystem fs = FileSystems.getDefault(); - try { - if (srcGlobPattern != null) { - srcMatcher = fs.getPathMatcher(GLOB_PREFIX + srcGlobPattern); - } else { - srcMatcher = acceptAll; - } - } catch (Exception e) { - LOGGER.error("Error creating matcher for sources with pattern: " + srcGlobPattern); - throw e; - } - - try { - if (testsGlobPattern != null) { - testsMatcher = fs.getPathMatcher(GLOB_PREFIX + testsGlobPattern); - } else { - testsMatcher = refuseAll; - } - } catch (Exception e) { - LOGGER.error("Error creating matcher for tests with pattern: " + testsGlobPattern); - throw e; - } - - try { - if (excludeGlobPattern != null) { - excludeMatcher = fs.getPathMatcher(GLOB_PREFIX + excludeGlobPattern); - } else { - excludeMatcher = refuseAll; - } - } catch (Exception e) { - LOGGER.error("Error creating matcher for exclusions with pattern: " + excludeGlobPattern); - throw e; - } - } - - public List collect(Path dir) throws IOException { - final List files = new ArrayList<>(); - Files.walkFileTree(dir, new FileCollector(dir, files)); - return files; - } - - private class FileCollector extends SimpleFileVisitor { - private final List files; - private final Path baseDir; - - private FileCollector(Path baseDir, List files) { - this.baseDir = baseDir; - this.files = files; - } - - @Override - public FileVisitResult visitFile(final Path file, BasicFileAttributes attrs) throws IOException { - Path absoluteFilePath = file; - Path relativeFilePath = baseDir.relativize(absoluteFilePath); - boolean isSrc = srcMatcher.matches(absoluteFilePath) || srcMatcher.matches(relativeFilePath); - boolean isExcluded = excludeMatcher.matches(absoluteFilePath) || excludeMatcher.matches(relativeFilePath); - if (isSrc && !isExcluded) { - boolean isTest = testsMatcher.matches(absoluteFilePath) || testsMatcher.matches(relativeFilePath); - files.add(new DefaultClientInputFile(absoluteFilePath, isTest, charset)); - } - - return super.visitFile(absoluteFilePath, attrs); - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - if (Files.isHidden(dir)) { - LOGGER.debug("Ignoring hidden directory: " + dir.toString()); - return FileVisitResult.SKIP_SUBTREE; - } - - return super.preVisitDirectory(dir, attrs); - } - } - - public static class DefaultClientInputFile implements ClientInputFile { - private final Path path; - private final boolean test; - private final Charset charset; - - public DefaultClientInputFile(Path path, boolean test, Charset charset) { - this.path = path; - this.test = test; - this.charset = charset; - } - - @Override - public boolean isTest() { - return test; - } - - @Override - public String getPath() { - return path.toString(); - } - - @Override - public Charset getCharset() { - return charset; - } - - @Override - public G getClientObject() { - return null; - } - - @Override - public InputStream inputStream() throws IOException { - return Files.newInputStream(path); - } - - @Override - public String contents() throws IOException { - return new String(Files.readAllBytes(path), charset); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/Main.java b/src/main/java/org/sonarlint/cli/Main.java deleted file mode 100644 index 82823ac..0000000 --- a/src/main/java/org/sonarlint/cli/Main.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli; - -import com.google.common.annotations.VisibleForTesting; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.ParseException; -import java.util.Map; -import org.sonarlint.cli.analysis.SonarLint; -import org.sonarlint.cli.analysis.SonarLintFactory; -import org.sonarlint.cli.config.ConfigurationReader; -import org.sonarlint.cli.report.ReportFactory; -import org.sonarlint.cli.util.Logger; -import org.sonarlint.cli.util.System2; -import org.sonarlint.cli.util.SystemInfo; -import org.sonarlint.cli.util.Util; - -import static org.sonarlint.cli.SonarProperties.PROJECT_HOME; - -public class Main { - static final int SUCCESS = 0; - static final int ERROR = 1; - - private static final Logger LOGGER = Logger.get(); - - private final Options opts; - private final ReportFactory reportFactory; - private BufferedReader inputReader; - private final InputFileFinder fileFinder; - private final Path projectHome; - private final SonarLintFactory sonarLintFactory; - - public Main(Options opts, SonarLintFactory sonarLintFactory, ReportFactory reportFactory, InputFileFinder fileFinder, Path projectHome) { - this.opts = opts; - this.sonarLintFactory = sonarLintFactory; - this.reportFactory = reportFactory; - this.fileFinder = fileFinder; - this.projectHome = projectHome; - } - - int run() { - if (opts.isHelp()) { - Options.printUsage(); - return SUCCESS; - } - - if (opts.isVersion()) { - Logger.get().info(SystemInfo.getVersion()); - return SUCCESS; - } - - reportFactory.setHtmlPath(opts.htmlReport()); - - LOGGER.setDebugEnabled(opts.isVerbose()); - LOGGER.setDisplayStackTrace(opts.showStack()); - - SystemInfo.print(LOGGER); - - if (opts.showStack()) { - LOGGER.info("Error stacktraces are turned on."); - } - - Stats stats = new Stats(); - try { - SonarLint sonarLint = sonarLintFactory.createSonarLint(projectHome, opts.isUpdate(), opts.isVerbose()); - sonarLint.start(opts.isUpdate()); - - Map props = Util.toMap(opts.properties()); - - if (opts.isInteractive()) { - runInteractive(stats, sonarLint, props, projectHome); - } else { - runOnce(stats, sonarLint, props, projectHome); - } - } catch (Exception e) { - displayExecutionResult(stats, "FAILURE"); - showError("Error executing SonarLint", e, opts.showStack(), opts.isVerbose()); - return ERROR; - } - - return SUCCESS; - } - - private static Path getProjectHome(System2 system) { - String projectHome = system.getProperty(PROJECT_HOME); - if (projectHome == null) { - throw new IllegalStateException("Can't find project home. System property not set: " + PROJECT_HOME); - } - return Paths.get(projectHome); - } - - private void runOnce(Stats stats, SonarLint sonarLint, Map props, Path projectHome) throws IOException { - stats.start(); - sonarLint.runAnalysis(props, reportFactory, fileFinder, projectHome); - sonarLint.stop(); - displayExecutionResult(stats, "SUCCESS"); - } - - private void runInteractive(Stats stats, SonarLint sonarLint, Map props, Path projectHome) throws IOException { - do { - stats.start(); - sonarLint.runAnalysis(props, reportFactory, fileFinder, projectHome); - displayExecutionResult(stats, "SUCCESS"); - } while (waitForUser()); - - sonarLint.stop(); - } - - private boolean waitForUser() throws IOException { - if (inputReader == null) { - inputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); - } - LOGGER.info(""); - LOGGER.info(""); - String line = inputReader.readLine(); - return line != null; - } - - public void setIn(InputStream in) { - inputReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - } - - public static void main(String[] args) { - execute(args, System2.INSTANCE); - } - - @VisibleForTesting - static void execute(String[] args, System2 system) { - Options parsedOpts; - try { - parsedOpts = Options.parse(args); - } catch (ParseException e) { - LOGGER.error("Error parsing arguments: " + e.getMessage(), e); - Options.printUsage(); - system.exit(ERROR); - return; - } - - Charset charset; - try { - if (parsedOpts.charset() != null) { - charset = Charset.forName(parsedOpts.charset()); - } else { - charset = Charset.defaultCharset(); - } - } catch (Exception e) { - LOGGER.error("Error creating charset: " + parsedOpts.charset(), e); - system.exit(ERROR); - return; - } - - InputFileFinder fileFinder = new InputFileFinder(parsedOpts.src(), parsedOpts.tests(), parsedOpts.exclusions(), charset); - ReportFactory reportFactory = new ReportFactory(charset); - ConfigurationReader reader = new ConfigurationReader(); - SonarLintFactory sonarLintFactory = new SonarLintFactory(reader); - - int ret = new Main(parsedOpts, sonarLintFactory, reportFactory, fileFinder, getProjectHome(system)).run(); - system.exit(ret); - return; - } - - private static void displayExecutionResult(Stats stats, String resultMsg) { - String dashes = "------------------------------------------------------------------------"; - LOGGER.info(dashes); - LOGGER.info("EXECUTION " + resultMsg); - LOGGER.info(dashes); - stats.stop(); - LOGGER.info(dashes); - } - - private static void showError(String message, Throwable e, boolean showStackTrace, boolean debug) { - if (showStackTrace) { - LOGGER.error(message, e); - if (!debug) { - LOGGER.error(""); - suggestDebugMode(); - } - } else { - LOGGER.error(message); - LOGGER.error(e.getMessage()); - String previousMsg = ""; - for (Throwable cause = e.getCause(); cause != null - && cause.getMessage() != null - && !cause.getMessage().equals(previousMsg); cause = cause.getCause()) { - LOGGER.error("Caused by: " + cause.getMessage()); - previousMsg = cause.getMessage(); - } - LOGGER.error(""); - LOGGER.error("To see the full stack trace of the errors, re-run SonarLint with the -e switch."); - if (!debug) { - suggestDebugMode(); - } - } - } - - private static void suggestDebugMode() { - LOGGER.error("Re-run SonarLint using the -X switch to enable full debug logging."); - } -} diff --git a/src/main/java/org/sonarlint/cli/Options.java b/src/main/java/org/sonarlint/cli/Options.java deleted file mode 100644 index aff6000..0000000 --- a/src/main/java/org/sonarlint/cli/Options.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli; - -import java.text.ParseException; -import java.util.Properties; -import org.sonarlint.cli.util.Logger; - -public class Options { - private static final Logger LOGGER = Logger.get(); - private Properties props = new Properties(); - private boolean verbose = false; - private boolean help = false; - private boolean version = false; - private boolean showStack = false; - private boolean interactive = false; - private String htmlReport = null; - private String src = null; - private String tests = ""; - private String exclusions = ""; - private String charset = null; - private boolean update = false; - private String task; - - public static Options parse(String[] args) throws ParseException { - Options options = new Options(); - - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (i == 0 && !arg.startsWith("-")) { - options.task = arg; - - } else if ("-h".equals(arg) || "--help".equals(arg)) { - options.help = true; - - } else if ("-v".equals(arg) || "--version".equals(arg)) { - options.version = true; - - } else if ("-i".equals(arg) || "--interactive".equals(arg)) { - options.interactive = true; - - } else if ("-e".equals(arg) || "--errors".equals(arg)) { - options.showStack = true; - - } else if ("-X".equals(arg) || "--debug".equals(arg)) { - options.verbose = true; - - } else if ("-u".equals(arg) || "--update".equals(arg)) { - options.update = true; - - } else if (arg.startsWith("-D") && !"-D".equals(arg)) { - arg = arg.substring(2); - appendPropertyTo(arg, options.props); - - } else { - i++; - - if ("--html-report".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - options.htmlReport = args[i]; - - } else if ("--charset".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - options.charset = args[i]; - - } else if ("--src".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - options.src = args[i]; - - } else if ("--tests".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - options.tests = args[i]; - - } else if ("--exclude".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - options.exclusions = args[i]; - - } else if ("-D".equals(arg) || "--define".equals(arg)) { - checkAdditionalArg(i, args.length, arg); - appendPropertyTo(args[i], options.props); - - } else { - throw new ParseException("Unrecognized option: " + arg, i); - } - } - } - - return options; - } - - private static void checkAdditionalArg(int i, int argsLength, String arg) throws ParseException { - if (i >= argsLength) { - throw new ParseException("Missing argument for option " + arg, i); - } - } - - public boolean isVerbose() { - return verbose; - } - - public boolean isInteractive() { - return interactive; - } - - public boolean isHelp() { - return help; - } - - public String charset() { - return charset; - } - - public String htmlReport() { - return htmlReport; - } - - public String src() { - return src; - } - - public String tests() { - return tests; - } - - public String exclusions() { - return exclusions; - } - - public boolean isUpdate() { - return update; - } - - public boolean isVersion() { - return version; - } - - public boolean showStack() { - return showStack; - } - - public Properties properties() { - return props; - } - - public String task() { - return task; - } - - public static void printUsage() { - LOGGER.info(""); - LOGGER.info("usage: sonarlint [options]"); - LOGGER.info(""); - LOGGER.info("Options:"); - LOGGER.info(" -u,--update Update binding with SonarQube server before analysis"); - LOGGER.info(" -D,--define Define property"); - LOGGER.info(" -e,--errors Produce execution error messages"); - LOGGER.info(" -h,--help Display help information"); - LOGGER.info(" -v,--version Display version information"); - LOGGER.info(" -X,--debug Produce execution debug output"); - LOGGER.info(" -i,--interactive Run interactively"); - LOGGER.info(" --html-report HTML report output path (relative or absolute)"); - LOGGER.info(" --src GLOB pattern to identify source files"); - LOGGER.info(" --tests GLOB pattern to identify test files"); - LOGGER.info(" --exclude GLOB pattern to exclude files"); - LOGGER.info(" --charset Character encoding of the source files"); - } - - private static void appendPropertyTo(String arg, Properties props) { - final String key; - final String value; - - int j = arg.indexOf('='); - if (j == -1) { - key = arg; - value = "true"; - } else { - key = arg.substring(0, j); - value = arg.substring(j + 1); - } - props.setProperty(key, value); - } -} diff --git a/src/main/java/org/sonarlint/cli/SonarProperties.java b/src/main/java/org/sonarlint/cli/SonarProperties.java deleted file mode 100644 index 8b27d6a..0000000 --- a/src/main/java/org/sonarlint/cli/SonarProperties.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli; - -public class SonarProperties { - public static final String PROPERTY_PROJECT_CONFIG_FILE = "sonar.projectConfigFile"; - - public static final String SONARLINT_HOME = "sonarlint.home"; - public static final String PROJECT_HOME = "project.home"; - - public static final String DEFAULT_SOURCES = "."; - public static final String DEFAULT_TESTS = "."; - public static final String DEFAULT_TESTS_INCLUSIONS = "**/*Test.*,**/test/**/*"; - - private SonarProperties() { - - } -} diff --git a/src/main/java/org/sonarlint/cli/Stats.java b/src/main/java/org/sonarlint/cli/Stats.java deleted file mode 100644 index 2613c7d..0000000 --- a/src/main/java/org/sonarlint/cli/Stats.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli; - -import org.sonarlint.cli.util.Logger; - -class Stats { - private static final Logger LOGGER = Logger.get(); - private long startTime; - - Stats start() { - startTime = System.currentTimeMillis(); - return this; - } - - Stats stop() { - long stopTime = System.currentTimeMillis() - startTime; - LOGGER.info("Total time: " + formatTime(stopTime)); - - System.gc(); - Runtime r = Runtime.getRuntime(); - long mb = 1024L * 1024; - LOGGER.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M"); - - return this; - } - - static String formatTime(long time) { - long h = time / (60 * 60 * 1000); - long m = (time - h * 60 * 60 * 1000) / (60 * 1000); - long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000; - long ms = time % 1000; - final String format; - if (h > 0) { - format = "%1$d:%2$02d:%3$02d.%4$03ds"; - } else if (m > 0) { - format = "%2$d:%3$02d.%4$03ds"; - } else { - format = "%3$d.%4$03ds"; - } - return String.format(format, h, m, s, ms); - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/ConnectedSonarLint.java b/src/main/java/org/sonarlint/cli/analysis/ConnectedSonarLint.java deleted file mode 100644 index a17267a..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/ConnectedSonarLint.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.CheckForNull; -import org.sonarlint.cli.config.SonarQubeServer; -import org.sonarlint.cli.report.ReportFactory; -import org.sonarlint.cli.util.Logger; -import org.sonarlint.cli.util.SystemInfo; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; -import org.sonarsource.sonarlint.core.client.api.connected.ConnectedAnalysisConfiguration; -import org.sonarsource.sonarlint.core.client.api.connected.ConnectedSonarLintEngine; -import org.sonarsource.sonarlint.core.client.api.connected.GlobalStorageStatus; -import org.sonarsource.sonarlint.core.client.api.connected.ModuleStorageStatus; -import org.sonarsource.sonarlint.core.client.api.connected.ServerConfiguration; -import org.sonarsource.sonarlint.core.tracking.CachingIssueTracker; -import org.sonarsource.sonarlint.core.tracking.CachingIssueTrackerImpl; -import org.sonarsource.sonarlint.core.tracking.Console; -import org.sonarsource.sonarlint.core.tracking.InMemoryIssueTrackerCache; -import org.sonarsource.sonarlint.core.tracking.IssueTrackable; -import org.sonarsource.sonarlint.core.tracking.IssueTrackerCache; -import org.sonarsource.sonarlint.core.tracking.ServerIssueTracker; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -import static org.sonarsource.sonarlint.core.client.api.util.FileUtils.toSonarQubePath; - -public class ConnectedSonarLint extends SonarLint { - private static final Logger LOGGER = Logger.get(); - - private final ConnectedSonarLintEngine engine; - private final String moduleKey; - private final SonarQubeServer server; - - ConnectedSonarLint(ConnectedSonarLintEngine engine, SonarQubeServer server, String moduleKey) { - this.engine = engine; - this.server = server; - this.moduleKey = moduleKey; - } - - @Override - public void start(boolean forceUpdate) { - GlobalStorageStatus globalStorageStatus = engine.getGlobalStorageStatus(); - - if (forceUpdate) { - LOGGER.info("Updating binding.."); - update(); - } else if (globalStorageStatus == null) { - LOGGER.info("No binding storage found. Updating.."); - update(); - } else if (globalStorageStatus.isStale()) { - LOGGER.info("Binding storage is stale. Updating.."); - update(); - } else { - checkModuleStatus(); - } - } - - private void checkModuleStatus() { - engine.allModulesByKey().keySet().stream() - .filter(key -> key.equals(moduleKey)) - .findAny() - .orElseThrow(() -> new IllegalStateException("Project key '" + moduleKey + "' not found in the binding storage. Maybe an update of the storage is needed with '-u'?")); - - ModuleStorageStatus moduleStorageStatus = engine.getModuleStorageStatus(moduleKey); - if (moduleStorageStatus == null) { - LOGGER.info("Updating data for module.."); - engine.updateModule(getServerConfiguration(server), moduleKey); - LOGGER.info("Module updated"); - } else if (moduleStorageStatus.isStale()) { - LOGGER.info("Module's data is stale. Updating.."); - engine.updateModule(getServerConfiguration(server), moduleKey); - LOGGER.info("Module updated"); - } - } - - private void update() { - engine.update(getServerConfiguration(server)); - engine.allModulesByKey().keySet().stream() - .filter(key -> key.equals(moduleKey)) - .findAny() - .orElseThrow(() -> new IllegalStateException("Project key '" + moduleKey + "' not found in the SonarQube server")); - updateModule(); - LOGGER.info("Binding updated"); - } - - private void updateModule() { - engine.updateModule(getServerConfiguration(server), moduleKey); - } - - private static ServerConfiguration getServerConfiguration(SonarQubeServer server) { - ServerConfiguration.Builder serverConfigBuilder = ServerConfiguration.builder() - .url(server.url()) - .userAgent("SonarLint CLI " + SystemInfo.getVersion()); - - String token = server.token(); - if (token != null) { - serverConfigBuilder.token(token); - } else { - serverConfigBuilder.credentials(server.login(), server.password()); - } - return serverConfigBuilder.build(); - } - - @Override - protected void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath) { - Date start = new Date(); - ConnectedAnalysisConfiguration config = new ConnectedAnalysisConfiguration(moduleKey, baseDirPath, baseDirPath.resolve(".sonarlint"), - inputFiles, properties); - IssueCollector collector = new IssueCollector(); - AnalysisResults result = engine.analyze(config, collector); - engine.downloadServerIssues(getServerConfiguration(server), moduleKey); - Collection trackables = matchAndTrack(baseDirPath, collector.get()); - generateReports(trackables, result, reportFactory, baseDirPath.getFileName().toString(), baseDirPath, start); - } - - Collection matchAndTrack(Path baseDirPath, Collection issues) { - Collection issuesWithFile = issues.stream().filter(issue -> issue.getInputFile() != null).collect(Collectors.toList()); - Collection relativePaths = getRelativePaths(baseDirPath, issuesWithFile); - Map> trackablesPerFile = getTrackablesPerFile(baseDirPath, issuesWithFile); - IssueTrackerCache cache = createCurrentIssueTrackerCache(relativePaths, trackablesPerFile); - return getCurrentTrackables(relativePaths, cache); - } - - private IssueTrackerCache createCurrentIssueTrackerCache(Collection relativePaths, Map> trackablesPerFile) { - IssueTrackerCache cache = new InMemoryIssueTrackerCache(); - CachingIssueTracker issueTracker = new CachingIssueTrackerImpl(cache); - trackablesPerFile.entrySet().forEach(entry -> issueTracker.matchAndTrackAsNew(entry.getKey(), entry.getValue())); - ServerIssueTracker serverIssueTracker = new ServerIssueTracker(new MyLogger(), new MyConsole(), issueTracker); - serverIssueTracker.update(engine, moduleKey, relativePaths); - return cache; - } - - private static List getCurrentTrackables(Collection relativePaths, IssueTrackerCache cache) { - return relativePaths.stream().flatMap(f -> cache.getCurrentTrackables(f).stream()) - .filter(trackable -> !trackable.isResolved()) - .collect(Collectors.toList()); - } - - private Map> getTrackablesPerFile(Path baseDirPath, Collection issues) { - return issues.stream() - .collect(Collectors.groupingBy(issue -> getRelativePath(baseDirPath, issue), Collectors.toList())) - .entrySet().stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> entry.getValue().stream() - .map(IssueTrackable::new) - .collect(Collectors.toCollection(ArrayList::new)))); - } - - private Collection getRelativePaths(Path baseDirPath, Collection issues) { - return issues.stream() - .map(issue -> getRelativePath(baseDirPath, issue)) - .collect(Collectors.toSet()); - } - - // note: engine.downloadServerIssues correctly figures out correct moduleKey and fileKey - @CheckForNull - String getRelativePath(Path baseDirPath, Issue issue) { - ClientInputFile inputFile = issue.getInputFile(); - if (inputFile == null) { - return null; - } - - return toSonarQubePath(baseDirPath.relativize(Paths.get(inputFile.getPath())).toString()); - } - - @Override - protected RuleDetails getRuleDetails(String ruleKey) { - return engine.getRuleDetails(ruleKey); - } - - @Override - public void stop() { - engine.stop(false); - } - - private static class MyLogger implements org.sonarsource.sonarlint.core.tracking.Logger { - @Override public void error(String message, Exception e) { - LOGGER.error(message, e); - } - - @Override public void debug(String message, Exception e) { - LOGGER.debug(message, e); - } - - @Override public void debug(String message) { - LOGGER.debug(message); - } - } - - private static class MyConsole implements Console { - @Override public void info(String message) { - LOGGER.info(message); - } - - @Override public void error(String message, Throwable t) { - LOGGER.error(message, t); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/DefaultLogOutput.java b/src/main/java/org/sonarlint/cli/analysis/DefaultLogOutput.java deleted file mode 100644 index 95097bf..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/DefaultLogOutput.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.client.api.common.LogOutput; - -class DefaultLogOutput implements LogOutput { - - private final Logger logger; - private final boolean verbose; - - public DefaultLogOutput(Logger logger, boolean verbose) { - this.logger = logger; - this.verbose = verbose; - } - - @Override - public void log(String formattedMessage, Level level) { - switch (level) { - case TRACE: - case DEBUG: - if (verbose) { - logger.debug(formattedMessage); - } - break; - case ERROR: - logger.error(formattedMessage); - break; - case INFO: - case WARN: - default: - logger.info(formattedMessage); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/IssueCollector.java b/src/main/java/org/sonarlint/cli/analysis/IssueCollector.java deleted file mode 100644 index ac6340a..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/IssueCollector.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import java.util.LinkedList; -import java.util.List; - -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; -import org.sonarsource.sonarlint.core.client.api.common.analysis.IssueListener; - -public class IssueCollector implements IssueListener { - private List issues = new LinkedList<>(); - - @Override - public void handle(Issue issue) { - issues.add(issue); - } - - public List get() { - return issues; - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/SonarLint.java b/src/main/java/org/sonarlint/cli/analysis/SonarLint.java deleted file mode 100644 index 048dc1a..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/SonarLint.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import org.sonarlint.cli.InputFileFinder; -import org.sonarlint.cli.report.ReportFactory; -import org.sonarlint.cli.report.Reporter; -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public abstract class SonarLint { - private static final Logger LOGGER = Logger.get(); - - public void start(boolean forceUpdate) { - // do nothing by default - } - - public void runAnalysis(Map properties, ReportFactory reportFactory, InputFileFinder finder, Path projectHome) { - List inputFiles; - try { - inputFiles = finder.collect(projectHome); - } catch (IOException e) { - throw new IllegalStateException("Error preparing list of files to analyze", e); - } - - if (inputFiles.isEmpty()) { - LOGGER.warn("No files to analyze"); - return; - } else { - LOGGER.debug(String.format("Submitting %d files for analysis", inputFiles.size())); - } - - doAnalysis(properties, reportFactory, inputFiles, projectHome); - } - - protected abstract RuleDetails getRuleDetails(String ruleKey); - - protected abstract void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath); - - public abstract void stop(); - - protected void generateReports(Collection trackables, AnalysisResults result, ReportFactory reportFactory, String projectName, Path baseDir, Date date) { - List reporters = reportFactory.createReporters(baseDir); - - for (Reporter r : reporters) { - r.execute(projectName, date, trackables, result, this::getRuleDetails); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/SonarLintFactory.java b/src/main/java/org/sonarlint/cli/analysis/SonarLintFactory.java deleted file mode 100644 index c300408..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/SonarLintFactory.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import com.google.common.annotations.VisibleForTesting; -import java.io.IOException; -import java.net.URL; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.sonarlint.cli.SonarProperties; -import org.sonarlint.cli.config.ConfigurationReader; -import org.sonarlint.cli.config.GlobalConfiguration; -import org.sonarlint.cli.config.ProjectConfiguration; -import org.sonarlint.cli.config.SonarQubeServer; -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.ConnectedSonarLintEngineImpl; -import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl; -import org.sonarsource.sonarlint.core.client.api.connected.ConnectedGlobalConfiguration; -import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration; -import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine; - -public class SonarLintFactory { - private static final Logger LOGGER = Logger.get(); - - private static final Path GLOBAL_CONFIGURATION_FILEPATH; - - private static final String GLOBAL_CONFIGURATION_FILENAME = "global.json"; - private static final String PROJECT_CONFIGURATION_FILENAME = "sonarlint.json"; - - private final ConfigurationReader configurationReader; - - static { - String home = System.getProperty("user.home"); - GLOBAL_CONFIGURATION_FILEPATH = Paths.get(home) - .resolve(".sonarlint") - .resolve("conf") - .resolve(GLOBAL_CONFIGURATION_FILENAME); - } - - public SonarLintFactory(ConfigurationReader configurationReader) { - this.configurationReader = configurationReader; - } - - public SonarLint createSonarLint(Path projectHome, boolean mustBeConnected, boolean verbose) { - return createSonarLint(GLOBAL_CONFIGURATION_FILEPATH, projectHome.resolve(PROJECT_CONFIGURATION_FILENAME), mustBeConnected, verbose); - } - - public SonarLint createSonarLint(Path globalConfigPath, Path projectConfigPath, boolean mustBeConnected, boolean verbose) { - if (!Files.exists(projectConfigPath)) { - if (mustBeConnected) { - throw new IllegalStateException("Can't update project - no binding defined in: " + projectConfigPath.toAbsolutePath()); - } - return createStandalone(verbose); - } - - ProjectConfiguration project = configurationReader.readProject(projectConfigPath); - - if (!Files.exists(globalConfigPath)) { - throw new IllegalStateException("Found project binding but there is no SonarQube server configured in: " + globalConfigPath.toAbsolutePath()); - } - - GlobalConfiguration global = configurationReader.readGlobal(globalConfigPath); - List servers = getServers(global); - - String projectKey = project.projectKey(); - SonarQubeServer server; - - if (project.serverId() == null) { - if (servers.size() > 1) { - throw new IllegalStateException( - String.format("No SonarQube server id is defined in the project binding (%s) and there are multiple servers defined in the global configuration", - projectConfigPath.toAbsolutePath())); - } - server = servers.get(0); - } else { - Optional optionalServer = servers.stream().filter(s -> s.id().equals(project.serverId())).findFirst(); - server = optionalServer - .orElseThrow(() -> new IllegalStateException(String.format("No SonarQube server configuration found in '%s' for the server id defined in the project binding: '%s'", - globalConfigPath.toAbsolutePath(), project.serverId()))); - } - - return createConnected(server, projectKey, verbose); - } - - private static List getServers(GlobalConfiguration conf) { - List servers = conf.servers(); - if (servers == null) { - return Collections.emptyList(); - } - - return servers; - } - - private static SonarLint createConnected(SonarQubeServer server, String projectKey, boolean verbose) { - LOGGER.info(String.format("Connected mode (%s)", projectKey)); - ConnectedGlobalConfiguration config = ConnectedGlobalConfiguration.builder() - .setLogOutput(new DefaultLogOutput(LOGGER, verbose)) - .setServerId(server.id()) - .build(); - ConnectedSonarLintEngineImpl engine = new ConnectedSonarLintEngineImpl(config); - return new ConnectedSonarLint(engine, server, projectKey); - } - - private static SonarLint createStandalone(boolean verbose) { - LOGGER.info("Standalone mode"); - URL[] plugins; - - try { - plugins = loadPlugins(); - } catch (Exception e) { - throw new IllegalStateException("Error loading plugins", e); - } - - StandaloneGlobalConfiguration config = StandaloneGlobalConfiguration.builder() - .addPlugins(plugins) - .setLogOutput(new DefaultLogOutput(LOGGER, verbose)) - .build(); - - StandaloneSonarLintEngine engine = new StandaloneSonarLintEngineImpl(config); - return new StandaloneSonarLint(engine); - } - - @VisibleForTesting - static URL[] loadPlugins() throws IOException { - String sonarlintHome = System.getProperty(SonarProperties.SONARLINT_HOME); - - if (sonarlintHome == null) { - throw new IllegalStateException("Can't find SonarLint home. System property not set: " + SonarProperties.SONARLINT_HOME); - } - - Path sonarLintHomePath = Paths.get(sonarlintHome); - Path pluginDir = sonarLintHomePath.resolve("plugins"); - - List pluginsUrls = new ArrayList<>(); - try (DirectoryStream directoryStream = Files.newDirectoryStream(pluginDir)) { - for (Path path : directoryStream) { - pluginsUrls.add(path.toUri().toURL()); - } - } - return pluginsUrls.toArray(new URL[pluginsUrls.size()]); - } - -} diff --git a/src/main/java/org/sonarlint/cli/analysis/StandaloneSonarLint.java b/src/main/java/org/sonarlint/cli/analysis/StandaloneSonarLint.java deleted file mode 100644 index 525f23f..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/StandaloneSonarLint.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.analysis; - -import java.nio.file.Path; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.sonarlint.cli.report.ReportFactory; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; -import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration; -import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine; -import org.sonarsource.sonarlint.core.tracking.IssueTrackable; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public class StandaloneSonarLint extends SonarLint { - private final StandaloneSonarLintEngine engine; - - public StandaloneSonarLint(StandaloneSonarLintEngine engine) { - this.engine = engine; - } - - @Override - protected void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath) { - Date start = new Date(); - - IssueCollector collector = new IssueCollector(); - StandaloneAnalysisConfiguration config = new StandaloneAnalysisConfiguration(baseDirPath, baseDirPath.resolve(".sonarlint"), - inputFiles, properties); - AnalysisResults result = engine.analyze(config, collector); - Collection trackables = collector.get().stream().map(IssueTrackable::new).collect(Collectors.toList()); - generateReports(trackables, result, reportFactory, baseDirPath.getFileName().toString(), baseDirPath, start); - } - - @Override - protected RuleDetails getRuleDetails(String ruleKey) { - return engine.getRuleDetails(ruleKey); - } - - @Override - public void stop() { - engine.stop(); - } -} diff --git a/src/main/java/org/sonarlint/cli/analysis/package-info.java b/src/main/java/org/sonarlint/cli/analysis/package-info.java deleted file mode 100644 index 61a3875..0000000 --- a/src/main/java/org/sonarlint/cli/analysis/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli.analysis; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/sonarlint/cli/config/ConfigurationReader.java b/src/main/java/org/sonarlint/cli/config/ConfigurationReader.java deleted file mode 100644 index b8f5cea..0000000 --- a/src/main/java/org/sonarlint/cli/config/ConfigurationReader.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.config; - -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import com.google.gson.GsonBuilder; -import java.io.IOException; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Set; - -import javax.annotation.Nullable; - -import org.apache.commons.lang.StringUtils; - -public class ConfigurationReader { - private static final String FAIL_PARSE_JSON = "Failed to parse JSON file: "; - - public GlobalConfiguration readGlobal(Path configFilePath) { - String contents = getContents(configFilePath); - GlobalConfiguration config; - - try { - config = new GsonBuilder().create().fromJson(contents, GlobalConfiguration.class); - } catch (RuntimeException ex) { - throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath, ex); - } - - return validate(config, configFilePath); - } - - public ProjectConfiguration readProject(Path configFilePath) { - String contents = getContents(configFilePath); - ProjectConfiguration config; - - try { - config = new GsonBuilder().create().fromJson(contents, ProjectConfiguration.class); - } catch (RuntimeException ex) { - throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath, ex); - } - - return validate(config, configFilePath); - } - - private static String getContents(Path filePath) { - try { - return Files.toString(filePath.toFile(), Charsets.UTF_8); - } catch (IOException e) { - throw new IllegalStateException("Error reading configuration file: " + filePath.toAbsolutePath(), e); - } - } - - private static ProjectConfiguration validate(@Nullable ProjectConfiguration projectConfig, Path configFilePath) { - if (projectConfig == null) { - throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath.toAbsolutePath()); - } - if (StringUtils.isEmpty(projectConfig.projectKey())) { - throw new IllegalStateException("Project binding must have a project key defined. Check the configuration in: " + configFilePath.toAbsolutePath()); - } - return projectConfig; - } - - private static GlobalConfiguration validate(@Nullable GlobalConfiguration globalConfig, Path configFilePath) { - Set serverUrls = new HashSet<>(); - - if (globalConfig == null) { - throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath.toAbsolutePath()); - } - if (globalConfig.servers() != null) { - for (SonarQubeServer s : globalConfig.servers()) { - if (StringUtils.isEmpty(s.url())) { - throw new IllegalStateException("Invalid SonarQube servers configuration: server URL must be defined. Check the configuration in: " + configFilePath); - } - - if (serverUrls.contains(s.url())) { - throw new IllegalStateException("Invalid SonarQube servers configuration: Each server configured must have a unique URL. Check the configuration in: " + configFilePath); - } - - serverUrls.add(s.url()); - } - } - return globalConfig; - } -} diff --git a/src/main/java/org/sonarlint/cli/config/GlobalConfiguration.java b/src/main/java/org/sonarlint/cli/config/GlobalConfiguration.java deleted file mode 100644 index 62f124a..0000000 --- a/src/main/java/org/sonarlint/cli/config/GlobalConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.config; - -import java.util.List; - -import javax.annotation.CheckForNull; - -public class GlobalConfiguration { - private List servers; - - @CheckForNull - public List servers() { - return servers; - } -} diff --git a/src/main/java/org/sonarlint/cli/config/ProjectConfiguration.java b/src/main/java/org/sonarlint/cli/config/ProjectConfiguration.java deleted file mode 100644 index 321162b..0000000 --- a/src/main/java/org/sonarlint/cli/config/ProjectConfiguration.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.config; - -import javax.annotation.CheckForNull; - -public class ProjectConfiguration { - private String serverId; - private String projectKey; - - @CheckForNull - public String serverId() { - return serverId; - } - - @CheckForNull - public String projectKey() { - return projectKey; - } -} diff --git a/src/main/java/org/sonarlint/cli/config/SonarQubeServer.java b/src/main/java/org/sonarlint/cli/config/SonarQubeServer.java deleted file mode 100644 index 3681393..0000000 --- a/src/main/java/org/sonarlint/cli/config/SonarQubeServer.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.config; - -public class SonarQubeServer { - private String id; - private String url; - private String token; - private String login; - private String password; - - public String id() { - return id; - } - - public String url() { - return url; - } - - public String token() { - return token; - } - - public String login() { - return login; - } - - public String password() { - return password; - } -} diff --git a/src/main/java/org/sonarlint/cli/config/package-info.java b/src/main/java/org/sonarlint/cli/config/package-info.java deleted file mode 100644 index ef18cc6..0000000 --- a/src/main/java/org/sonarlint/cli/config/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli.config; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/sonarlint/cli/package-info.java b/src/main/java/org/sonarlint/cli/package-info.java deleted file mode 100644 index 02080bc..0000000 --- a/src/main/java/org/sonarlint/cli/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/sonarlint/cli/report/CategoryReport.java b/src/main/java/org/sonarlint/cli/report/CategoryReport.java deleted file mode 100644 index ede135a..0000000 --- a/src/main/java/org/sonarlint/cli/report/CategoryReport.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -public final class CategoryReport { - private final IssueCategory category; - private final IssueVariation total = new IssueVariation(); - - CategoryReport(IssueCategory category) { - this.category = category; - } - - public IssueVariation getTotal() { - return total; - } - - public IssueCategory getCategory() { - return category; - } - - public String getName() { - return category.getName(); - } - - public Severity getSeverity() { - return category.getSeverity(); - } - - public String getRuleKey() { - return category.getRuleKey(); - } - - @Override - public String toString() { - return new StringBuilder() - .append(super.toString()) - .append("[reportRuleKey=") - .append(category) - .append(",total=") - .append(total) - .append("]") - .toString(); - } -} diff --git a/src/main/java/org/sonarlint/cli/report/CategoryReportComparator.java b/src/main/java/org/sonarlint/cli/report/CategoryReportComparator.java deleted file mode 100644 index 89c616e..0000000 --- a/src/main/java/org/sonarlint/cli/report/CategoryReportComparator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.Comparator; - -class CategoryReportComparator implements Comparator { - @Override - public int compare(CategoryReport o1, CategoryReport o2) { - if (bothHaveNoNewIssue(o1, o2)) { - return compareByRuleSeverityAndKey(o1, o2); - } else if (bothHaveNewIssues(o1, o2)) { - if (sameSeverity(o1, o2) && !sameNewIssueCount(o1, o2)) { - return compareNewIssueCount(o1, o2); - } else { - return compareByRuleSeverityAndKey(o1, o2); - } - } else { - return compareNewIssueCount(o1, o2); - } - } - - private static int compareByRuleSeverityAndKey(CategoryReport o1, CategoryReport o2) { - return o1.getCategory().compareTo(o2.getCategory()); - } - - private static boolean sameNewIssueCount(CategoryReport o1, CategoryReport o2) { - return o2.getTotal().getNewIssuesCount() == o1.getTotal().getNewIssuesCount(); - } - - private static boolean sameSeverity(CategoryReport o1, CategoryReport o2) { - return o1.getSeverity().equals(o2.getSeverity()); - } - - private static int compareNewIssueCount(CategoryReport o1, CategoryReport o2) { - return o2.getTotal().getNewIssuesCount() - o1.getTotal().getNewIssuesCount(); - } - - private static boolean bothHaveNewIssues(CategoryReport o1, CategoryReport o2) { - return o1.getTotal().getNewIssuesCount() > 0 && o2.getTotal().getNewIssuesCount() > 0; - } - - private static boolean bothHaveNoNewIssue(CategoryReport o1, CategoryReport o2) { - return o1.getTotal().getNewIssuesCount() == 0 && o2.getTotal().getNewIssuesCount() == 0; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/ConsoleReport.java b/src/main/java/org/sonarlint/cli/report/ConsoleReport.java deleted file mode 100644 index c82c40f..0000000 --- a/src/main/java/org/sonarlint/cli/report/ConsoleReport.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.Collection; -import java.util.Date; -import java.util.function.Function; -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public class ConsoleReport implements Reporter { - - public static final String HEADER = "------------- SonarLint Report -------------"; - private static final Logger LOGGER = Logger.get(); - - public static final String CONSOLE_REPORT_ENABLED_KEY = "sonar.issuesReport.console.enable"; - private static final int LEFT_PAD = 10; - - ConsoleReport() { - - } - - private static class Report { - int totalIssues = 0; - int blockerIssues = 0; - int criticalIssues = 0; - int majorIssues = 0; - int minorIssues = 0; - int infoIssues = 0; - - public void process(Issue issue) { - totalIssues++; - switch (issue.getSeverity()) { - case "BLOCKER": - blockerIssues++; - break; - case "CRITICAL": - criticalIssues++; - break; - case "MAJOR": - majorIssues++; - break; - case "MINOR": - minorIssues++; - break; - case "INFO": - infoIssues++; - break; - default: - throw new IllegalStateException("Unknown severity: " + issue.getSeverity()); - } - } - - public boolean hasNoIssues() { - return totalIssues == 0; - } - } - - @Override - public void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer) { - Report r = new Report(); - for (Trackable trackable : trackables) { - r.process(trackable.getIssue()); - } - printReport(r, result); - } - - public void printReport(Report r, AnalysisResults result) { - StringBuilder sb = new StringBuilder(); - - sb.append("\n\n" + HEADER + "\n\n"); - if (result.fileCount() == 0) { - sb.append(" No files analyzed\n"); - } else if (r.hasNoIssues()) { - sb.append(" No issues to display "); - filesAnalyzed(sb, result.fileCount()); - sb.append("\n"); - } else { - printIssues(r, sb, result.fileCount()); - } - sb.append("\n-------------------------------------------\n\n"); - - LOGGER.info(sb.toString()); - } - - private static void filesAnalyzed(StringBuilder sb, int num) { - sb.append("(").append(num); - if (num > 1) { - sb.append(" files analyzed"); - } else { - sb.append(" file analyzed"); - } - sb.append(")"); - } - - private static void printIssues(Report r, StringBuilder sb, int filesAnalyzed) { - int issues = r.totalIssues; - sb.append(leftPad(Integer.toString(issues), LEFT_PAD)) - .append(" issue"); - if (issues > 1) { - sb.append("s"); - } - sb.append(" "); - - filesAnalyzed(sb, filesAnalyzed); - sb.append("\n\n"); - printIssues(sb, r.blockerIssues, "blocker"); - printIssues(sb, r.criticalIssues, "critical"); - printIssues(sb, r.majorIssues, "major"); - printIssues(sb, r.minorIssues, "minor"); - printIssues(sb, r.infoIssues, "info"); - } - - private static void printIssues(StringBuilder sb, int issueCount, String severityLabel) { - if (issueCount > 0) { - sb.append(leftPad(Integer.toString(issueCount), LEFT_PAD)).append(" ").append(severityLabel).append("\n"); - } - } - - private static String leftPad(String str, int spaces) { - StringBuilder sb = new StringBuilder(); - - for (int i = spaces; i > 0; i--) { - sb.append(" "); - } - - sb.append(str); - return sb.toString(); - } -} diff --git a/src/main/java/org/sonarlint/cli/report/HtmlReport.java b/src/main/java/org/sonarlint/cli/report/HtmlReport.java deleted file mode 100644 index 39888c5..0000000 --- a/src/main/java/org/sonarlint/cli/report/HtmlReport.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import freemarker.template.Configuration; -import freemarker.template.Template; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import org.apache.commons.io.FileUtils; -import org.sonarlint.cli.util.Logger; -import org.sonarlint.cli.util.Util; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public class HtmlReport implements Reporter { - private static final Logger LOGGER = Logger.get(); - private final Path reportFile; - private final Path reportDir; - private final Charset charset; - private final Path basePath; - - HtmlReport(Path basePath, Path reportFile, Charset charset) { - this.basePath = basePath; - this.charset = charset; - this.reportDir = reportFile.getParent().toAbsolutePath(); - this.reportFile = reportFile.toAbsolutePath(); - } - - @Override - public void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer) { - IssuesReport report = new IssuesReport(basePath, charset); - for (Trackable trackable : trackables) { - report.addIssue(trackable); - } - report.setTitle(projectName); - report.setDate(date); - report.setFilesAnalyzed(result.fileCount()); - copyRuleHtmlDescriptions(ruleDescriptionProducer, report); - print(report); - } - - private void copyRuleHtmlDescriptions(Function ruleDescriptionProducer, IssuesReport report) { - try { - Set ruleKeys = report.getSummary().getTotalByRuleKey().keySet(); - Path target = reportDir.resolve("sonarlintreport_rules"); - Files.createDirectories(target); - copyDependency(target, "rule.css"); - for (String ruleKey : ruleKeys) { - RuleDetails ruleDetails = ruleDescriptionProducer.apply(ruleKey); - String htmlDescription = ruleDetails.getHtmlDescription(); - String extendedDescription = ruleDetails.getExtendedDescription(); - if (!extendedDescription.isEmpty()) { - htmlDescription += "\n
" + extendedDescription + "
"; - } - FileUtils.write(target.resolve(Util.escapeFileName(ruleKey) + ".html").toFile(), - "

" + ruleDetails.getName() + " (" - + ruleKey - + ")

" + htmlDescription - + "
", - StandardCharsets.UTF_8); - } - } catch (IOException e) { - throw new IllegalStateException("Unable to copy rule descriptions", e); - } - } - - public void print(IssuesReport report) { - LOGGER.debug("Generating SonarLint Report to: " + reportFile); - writeToFile(report, reportFile); - LOGGER.info("SonarLint HTML Report generated: " + reportFile); - try { - copyDependencies(reportDir); - } catch (Exception e) { - throw new IllegalStateException("Fail to copy HTML report resources to: " + reportDir, e); - } - } - - private static void writeToFile(IssuesReport report, Path toFile) { - try { - Configuration cfg = new Configuration(Configuration.VERSION_2_3_25); - cfg.setClassForTemplateLoading(HtmlReport.class, ""); - - Map root = new HashMap<>(); - root.put("report", report); - - Template template = cfg.getTemplate("sonarlintreport.ftl"); - - try (FileOutputStream fos = new FileOutputStream(toFile.toFile()); - Writer writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) { - template.process(root, writer); - writer.flush(); - } - } catch (Exception e) { - throw new IllegalStateException("Fail to generate HTML Issues Report to: " + toFile, e); - } - } - - private void copyDependencies(Path toDir) throws URISyntaxException, IOException { - Path target = toDir.resolve("sonarlintreport_files"); - Files.createDirectories(target); - - // I don't know how to extract a directory from classpath, that's why an exhaustive list of files is provided here : - copyDependency(target, "sonar.eot"); - copyDependency(target, "sonar.svg"); - copyDependency(target, "sonar.ttf"); - copyDependency(target, "sonar.woff"); - copyDependency(target, "favicon.ico"); - copyDependency(target, "PRJ.png"); - copyDependency(target, "DIR.png"); - copyDependency(target, "FIL.png"); - copyDependency(target, "jquery.min.js"); - copyDependency(target, "sep12.png"); - copyDependency(target, "sonar.css"); - copyDependency(target, "sonarlint.png"); - } - - private void copyDependency(Path target, String filename) { - String resource = "sonarlintreport_files/" + filename; - try (InputStream in = getClass().getResourceAsStream(resource)) { - Files.copy(in, target.resolve(filename), StandardCopyOption.REPLACE_EXISTING); - - } catch (IOException e) { - throw new IllegalStateException("Fail to copy file " + filename + " to " + target, e); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/report/IssueCategory.java b/src/main/java/org/sonarlint/cli/report/IssueCategory.java deleted file mode 100644 index fb272ff..0000000 --- a/src/main/java/org/sonarlint/cli/report/IssueCategory.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.Objects; - -/** - * A same rule can be present with different severity if severity was manually changed so we categorize by rule key and severity - * - */ -public class IssueCategory implements Comparable { - private final String ruleKey; - private final Severity severity; - private final String name; - - IssueCategory(String ruleKey, Severity severity, String name) { - this.ruleKey = ruleKey; - this.severity = severity; - this.name = name; - } - - public String getRuleKey() { - return ruleKey; - } - - public String getName() { - return name; - } - - public Severity getSeverity() { - return severity; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IssueCategory that = (IssueCategory) o; - return Objects.equals(ruleKey, that.ruleKey) && Objects.equals(severity, that.severity); - } - - @Override - public int hashCode() { - int result = ruleKey.hashCode(); - result = 31 * result + severity.hashCode(); - return result; - } - - @Override - public int compareTo(IssueCategory o) { - if (severity == o.getSeverity()) { - return getRuleKey().compareTo(o.getRuleKey()); - } - return o.getSeverity().compareTo(severity); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - return sb.append(super.toString()) - .append("[") - .append("rule=").append(ruleKey).append(",severity=").append(severity) - .append("]").toString(); - } -} diff --git a/src/main/java/org/sonarlint/cli/report/IssueVariation.java b/src/main/java/org/sonarlint/cli/report/IssueVariation.java deleted file mode 100644 index 2a96bf5..0000000 --- a/src/main/java/org/sonarlint/cli/report/IssueVariation.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -public class IssueVariation { - - private int countInCurrentAnalysis; - private int newIssuesCount; - private int resolvedIssuesCount; - - IssueVariation() { - } - - IssueVariation(int currentCount, int newCount, int resolvedCount) { - this.countInCurrentAnalysis = currentCount; - this.newIssuesCount = newCount; - this.resolvedIssuesCount = resolvedCount; - } - - public int getCountInCurrentAnalysis() { - return countInCurrentAnalysis; - } - - public void incrementCountInCurrentAnalysis() { - this.countInCurrentAnalysis++; - } - - public int getNewIssuesCount() { - return newIssuesCount; - } - - public void incrementNewIssuesCount() { - this.newIssuesCount++; - } - - public int getResolvedIssuesCount() { - return resolvedIssuesCount; - } - - public void incrementResolvedIssuesCount() { - this.resolvedIssuesCount++; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + countInCurrentAnalysis; - result = prime * result + newIssuesCount; - result = prime * result + resolvedIssuesCount; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - IssueVariation other = (IssueVariation) obj; - - return countInCurrentAnalysis == other.countInCurrentAnalysis - && newIssuesCount == other.newIssuesCount - && resolvedIssuesCount == other.resolvedIssuesCount; - } - - @Override - public String toString() { - return new StringBuilder() - .append(super.toString()) - .append("[countInCurrentAnalysis=") - .append(countInCurrentAnalysis) - .append(",newIssuesCount=") - .append(newIssuesCount) - .append(",resolvedIssuesCount=") - .append(resolvedIssuesCount) - .append("]") - .toString(); - } - -} diff --git a/src/main/java/org/sonarlint/cli/report/IssuesReport.java b/src/main/java/org/sonarlint/cli/report/IssuesReport.java deleted file mode 100644 index ae8807e..0000000 --- a/src/main/java/org/sonarlint/cli/report/IssuesReport.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -import org.sonarlint.cli.report.source.HtmlSourceDecorator; -import org.sonarlint.cli.util.Util; -import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public class IssuesReport { - - private String title; - private Date date; - private int filesAnalyzed; - private final ReportSummary summary = new ReportSummary(); - private final Map resourceReportsByFilePath = new HashMap<>(); - private final Map ruleNameByKey = new HashMap<>(); - private final Charset charset; - private int id = 0; - private Path basePath; - - IssuesReport(Path basePath, Charset charset) { - this.basePath = basePath; - this.charset = charset; - } - - public boolean noIssues() { - return summary.getTotal().getCountInCurrentAnalysis() == 0; - } - - public ReportSummary getSummary() { - return summary; - } - - public boolean noFiles() { - return filesAnalyzed == 0; - } - - public int getFilesAnalyzed() { - return filesAnalyzed; - } - - public void setFilesAnalyzed(int num) { - this.filesAnalyzed = num; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public Map getResourceReportsByResource() { - return resourceReportsByFilePath; - } - - public List getResourceReports() { - return new ArrayList<>(resourceReportsByFilePath.values()); - } - - public List getResourcesWithReport() { - return new ArrayList<>(resourceReportsByFilePath.keySet()); - } - - public String getRuleName(String ruleKey) { - return ruleNameByKey.get(ruleKey); - } - - public void addIssue(Trackable trackable) { - Issue issue = trackable.getIssue(); - Long millis = trackable.getServerIssueKey() != null ? trackable.getCreationDate() : null; - RichIssue richIssue = new RichIssueImpl(issue, id, millis); - id++; - ruleNameByKey.put(issue.getRuleKey(), issue.getRuleName()); - - Path filePath; - ClientInputFile inputFile = issue.getInputFile(); - if (inputFile == null) { - // issue on project (no specific file) - filePath = Paths.get(""); - } else { - filePath = Paths.get(inputFile.getPath()); - } - ResourceReport report = getOrCreate(filePath); - summary.addIssue(richIssue); - report.addIssue(richIssue); - } - - private static class RichIssueImpl implements RichIssue { - - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMMMM d, y K:m a"); - - private final Issue wrapped; - private final int id; - private final String creationDate; - - public RichIssueImpl(Issue wrapped, int id, @Nullable Long creationDateMillis) { - this.wrapped = wrapped; - this.id = id; - this.creationDate = creationDateMillis != null ? DATE_FORMAT.format(new Date(creationDateMillis)) : null; - } - - @Override - public String getSeverity() { - return wrapped.getSeverity(); - } - - @Override - public String getType() { - return wrapped.getType(); - } - - @Override - public Integer getStartLine() { - return wrapped.getStartLine() != null ? wrapped.getStartLine() : 1; - } - - @Override - public Integer getStartLineOffset() { - return wrapped.getStartLineOffset(); - } - - @Override - public Integer getEndLine() { - return wrapped.getEndLine() != null ? wrapped.getEndLine() : getStartLine(); - } - - @Override - public Integer getEndLineOffset() { - return wrapped.getEndLineOffset(); - - } - - @Override - public List flows() { - return wrapped.flows(); - } - - @Override - public String getMessage() { - return wrapped.getMessage(); - } - - @Override - public String getRuleKey() { - return wrapped.getRuleKey(); - } - - @Override - public String getRuleName() { - return wrapped.getRuleName(); - } - - @Override - public ClientInputFile getInputFile() { - return wrapped.getInputFile(); - } - - @Override - public int id() { - return id; - } - - @Override - public String ruleDescriptionFileName() { - return Util.escapeFileName(wrapped.getRuleKey()) + ".html"; - } - - @Override - public String creationDate() { - return creationDate; - } - } - - private ResourceReport getOrCreate(Path filePath) { - ResourceReport report = resourceReportsByFilePath.get(filePath); - if (report != null) { - return report; - } - report = new ResourceReport(basePath, filePath); - resourceReportsByFilePath.put(filePath, report); - return report; - } - - public List getEscapedSource(@Nullable Path filePath) { - if (filePath == null) { - return Collections.emptyList(); - } - List lines; - try { - if (!filePath.toFile().exists()) { - // invalid, directory, project issue, ... - return Collections.emptyList(); - } - - lines = Files.readAllLines(filePath, charset); - } catch (IOException e) { - throw new IllegalStateException("unable to read source code of file: " + filePath, e); - } - - ResourceReport resourceReport = resourceReportsByFilePath.get(filePath); - if (resourceReport == null) { - throw new IllegalStateException("file has no associated report: " + filePath); - } - - List escapedLines = new ArrayList<>(lines.size()); - for (int i = 0; i < lines.size(); i++) { - String line = lines.get(i); - final int currentLineIdx = i + 1; - List issuesAtLine = resourceReport.getIssues().stream() - .filter(issue -> issue.getStartLine() <= currentLineIdx && currentLineIdx <= issue.getEndLine()) - .collect(Collectors.toList()); - - escapedLines.add(HtmlSourceDecorator.getDecoratedSourceAsHtml(line, currentLineIdx, issuesAtLine)); - } - return escapedLines; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/JsonReport.java b/src/main/java/org/sonarlint/cli/report/JsonReport.java deleted file mode 100644 index ef8950f..0000000 --- a/src/main/java/org/sonarlint/cli/report/JsonReport.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import com.google.gson.JsonObject; -import com.google.gson.JsonArray; -import java.io.PrintStream; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Arrays; -import java.util.function.Function; -import org.sonarlint.cli.util.Logger; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -public class JsonReport implements Reporter { - - private static final List VALID_RULE_DETAIL_TYPES = Arrays.asList( - "BUG", - "VULNERABILITY" - ); - - JsonReport() { - - } - - @Override - public void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer) { - for (Trackable trackable : trackables) { - Issue issue = trackable.getIssue(); - RuleDetails ruleDetails = ruleDescriptionProducer.apply(issue.getRuleKey()); - - if (VALID_RULE_DETAIL_TYPES.contains(ruleDetails.getType())) { - JsonObject json = new JsonObject(); - json.addProperty("type", "issue"); - json.addProperty("check_name", issue.getRuleKey()); - json.addProperty("severity", ruleDetails.getSeverity().toLowerCase()); - json.addProperty("description", issue.getMessage()); - - JsonObject content = new JsonObject(); - json.add("content", content); - content.addProperty("body", ruleDetails.getHtmlDescription()); - // // ruleDetails.getExtendedDescription(); - - JsonObject location = new JsonObject(); - json.add("location", location); - - // Code Climate CLI expects relative path to file - location.addProperty("path", issue.getInputFile().getPath().replaceFirst("^/code-read-write/", "")); - - JsonObject lines = new JsonObject(); - location.add("lines", lines); - - if (issue.getStartLine() != null) { - lines.addProperty("begin", issue.getStartLine()); - - if (issue.getEndLine() != null) { - lines.addProperty("end", issue.getEndLine()); - } else { - lines.addProperty("end", 1); - } - } else { - lines.addProperty("begin", 1); - lines.addProperty("end", 1); - } - - String category; - switch (ruleDetails.getType()) { - case "VULNERABILITY": { - category = "Security"; - break; - } - default: { - category = "Bug Risk"; - break; - } - } - JsonArray categories = new JsonArray(); - categories.add(category); - json.add("categories", categories); - - System.out.println(json.toString() + "\0"); - } - } - } -} diff --git a/src/main/java/org/sonarlint/cli/report/ReportFactory.java b/src/main/java/org/sonarlint/cli/report/ReportFactory.java deleted file mode 100644 index 1150a54..0000000 --- a/src/main/java/org/sonarlint/cli/report/ReportFactory.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.LinkedList; -import java.util.List; -import javax.annotation.Nullable; - -public class ReportFactory { - private static final String DEFAULT_REPORT_PATH = ".sonarlint/sonarlint-report.html"; - private String htmlPath = null; - private Charset charset; - - public ReportFactory(Charset charset) { - this.charset = charset; - } - - public List createReporters(Path basePath) { - List list = new LinkedList<>(); - - list.add(new ConsoleReport()); - list.add(new HtmlReport(basePath, getReportFile(basePath), charset)); - list.add(new JsonReport()); - - return list; - } - - public void setHtmlPath(@Nullable String path) { - htmlPath = path; - } - - Path getReportFile(Path basePath) { - Path reportPath; - - if (htmlPath != null) { - reportPath = Paths.get(htmlPath); - - if (!reportPath.isAbsolute()) { - reportPath = basePath.resolve(reportPath).toAbsolutePath(); - } - } else { - reportPath = basePath.resolve(DEFAULT_REPORT_PATH); - } - - try { - Files.createDirectories(reportPath.getParent()); - } catch (IOException e) { - throw new IllegalStateException("Fail to create the directory " + reportPath.getParent(), e); - } - - return reportPath; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/ReportSummary.java b/src/main/java/org/sonarlint/cli/report/ReportSummary.java deleted file mode 100644 index 62778df..0000000 --- a/src/main/java/org/sonarlint/cli/report/ReportSummary.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.sonarlint.cli.util.Util; - -public class ReportSummary { - - private final IssueVariation total = new IssueVariation(); - - private final Map reportByCategory = new LinkedHashMap<>(); - private final Map totalByRuleKey = new LinkedHashMap<>(); - private final Map totalBySeverity = new LinkedHashMap<>(); - - ReportSummary() { - } - - public void addIssue(RichIssue issue) { - Severity severity = Severity.create(issue.getSeverity()); - IssueCategory category = new IssueCategory(issue.getRuleKey(), severity, issue.getRuleName()); - - IssueVariation byRuleKey = Util.getOrCreate(totalByRuleKey, issue.getRuleKey(), IssueVariation::new); - CategoryReport byCategory = getOrCreate(reportByCategory, category); - IssueVariation bySeverity = Util.getOrCreate(totalBySeverity, issue.getSeverity(), IssueVariation::new); - - total.incrementCountInCurrentAnalysis(); - byCategory.getTotal().incrementCountInCurrentAnalysis(); - byRuleKey.incrementCountInCurrentAnalysis(); - bySeverity.incrementCountInCurrentAnalysis(); - } - - public IssueVariation getTotal() { - return total; - } - - public Map getTotalBySeverity() { - return totalBySeverity; - } - - public Map getTotalByRuleKey() { - return totalByRuleKey; - } - - private static CategoryReport getOrCreate(Map m, IssueCategory key) { - CategoryReport report = m.get(key); - if (report != null) { - return report; - } - - report = new CategoryReport(key); - m.put(key, report); - return report; - } - - public List getCategoryReports() { - List result = new ArrayList<>(reportByCategory.values()); - Collections.sort(result, new CategoryReportComparator()); - return result; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/Reporter.java b/src/main/java/org/sonarlint/cli/report/Reporter.java deleted file mode 100644 index 957d249..0000000 --- a/src/main/java/org/sonarlint/cli/report/Reporter.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.Collection; -import java.util.Date; -import java.util.function.Function; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; -import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; -import org.sonarsource.sonarlint.core.tracking.Trackable; - -@FunctionalInterface -public interface Reporter { - void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer); -} diff --git a/src/main/java/org/sonarlint/cli/report/ResourceReport.java b/src/main/java/org/sonarlint/cli/report/ResourceReport.java deleted file mode 100644 index 18c76d7..0000000 --- a/src/main/java/org/sonarlint/cli/report/ResourceReport.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonarlint.cli.util.MutableInt; - -import static org.sonarlint.cli.util.Util.getOrCreate; - -public final class ResourceReport { - private final Path filePath; - private final IssueVariation total = new IssueVariation(); - private final List issues = new ArrayList<>(); - - private final Map reportByCategory = new HashMap<>(); - private final Map> issuesPerLine = new HashMap<>(); - - private final Map issuesByRule = new HashMap<>(); - private final EnumMap issuesBySeverity = new EnumMap<>(Severity.class); - private Path basePath; - - ResourceReport(Path basePath, @Nullable Path filePath) { - this.basePath = basePath; - this.filePath = filePath; - } - - @CheckForNull - public Path getPath() { - return filePath; - } - - public String getName() { - return basePath.toAbsolutePath().relativize(filePath.toAbsolutePath()).toString(); - } - - public String getType() { - if (filePath == null || filePath.equals(Paths.get(""))) { - return "PRJ"; - } else { - return "FIL"; - } - } - - public IssueVariation getTotal() { - return total; - } - - public List getIssues() { - return issues; - } - - public Map> getIssuesPerLine() { - return issuesPerLine; - } - - public List getIssuesAtLine(int lineId) { - if (issuesPerLine.containsKey(lineId)) { - return issuesPerLine.get(lineId); - } - return Collections.emptyList(); - } - - public void addIssue(RichIssue issue) { - Severity severity = Severity.create(issue.getSeverity()); - String ruleKey = issue.getRuleKey(); - IssueCategory reportRuleKey = new IssueCategory(ruleKey, severity, issue.getRuleName()); - - initMaps(reportRuleKey); - issues.add(issue); - Integer line = issue.getStartLine(); - line = line != null ? line : 0; - - getOrCreate(issuesPerLine, line, LinkedList::new).add(issue); - getOrCreate(issuesByRule, ruleKey, MutableInt::new).inc(); - getOrCreate(issuesBySeverity, severity, MutableInt::new).inc(); - - reportByCategory.get(reportRuleKey).getTotal().incrementCountInCurrentAnalysis(); - total.incrementCountInCurrentAnalysis(); - } - - private void initMaps(IssueCategory reportRuleKey) { - if (!reportByCategory.containsKey(reportRuleKey)) { - reportByCategory.put(reportRuleKey, new CategoryReport(reportRuleKey)); - } - } - - public boolean isDisplayableLine(@Nullable Integer lineNumber) { - if (lineNumber == null || lineNumber < 1) { - return false; - } - for (int i = lineNumber - 2; i <= lineNumber + 2; i++) { - if (hasIssues(i)) { - return true; - } - } - return false; - } - - private boolean hasIssues(Integer lineId) { - List issuesAtLine = issuesPerLine.get(lineId); - return issuesAtLine != null && !issuesAtLine.isEmpty(); - } - - public List getCategoryReports() { - List result = new ArrayList<>(reportByCategory.values()); - Collections.sort(result, new CategoryReportComparator()); - return result; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/RichIssue.java b/src/main/java/org/sonarlint/cli/report/RichIssue.java deleted file mode 100644 index 32f9030..0000000 --- a/src/main/java/org/sonarlint/cli/report/RichIssue.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; - -/** - * Issue, enriched with additional information. - */ -public interface RichIssue extends Issue { - - int id(); - - String ruleDescriptionFileName(); - - String creationDate(); - -} diff --git a/src/main/java/org/sonarlint/cli/report/Severity.java b/src/main/java/org/sonarlint/cli/report/Severity.java deleted file mode 100644 index 34b900f..0000000 --- a/src/main/java/org/sonarlint/cli/report/Severity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report; - -import java.util.HashMap; -import java.util.Map; - -enum Severity { - INFO, - MINOR, - MAJOR, - CRITICAL, - BLOCKER; - - private static final Map MAP; - - Severity() { - } - - static { - MAP = new HashMap<>(); - for (Severity s : Severity.values()) { - MAP.put(s.name(), s); - } - } - - static Severity create(String severity) { - Severity s = MAP.get(severity); - if (s == null) { - throw new IllegalArgumentException("Invalid severity: " + severity); - } - return s; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/package-info.java b/src/main/java/org/sonarlint/cli/report/package-info.java deleted file mode 100644 index d34c03d..0000000 --- a/src/main/java/org/sonarlint/cli/report/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli.report; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/sonarlint/cli/report/source/CharactersReader.java b/src/main/java/org/sonarlint/cli/report/source/CharactersReader.java deleted file mode 100644 index 445393d..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/CharactersReader.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report.source; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.Deque; - -class CharactersReader { - - static final int END_OF_STREAM = -1; - - private final BufferedReader stringBuffer; - private final Deque openTags; - - private int currentValue; - private int currentIndex = -1; - - public CharactersReader(BufferedReader stringBuffer) { - this.stringBuffer = stringBuffer; - this.openTags = new ArrayDeque<>(); - } - - boolean readNextChar() throws IOException { - currentValue = stringBuffer.read(); - currentIndex++; - return currentValue != END_OF_STREAM; - } - - int getCurrentValue() { - return currentValue; - } - - int getCurrentIndex() { - return currentIndex; - } - - void registerOpenTag(String textType) { - openTags.push(textType); - } - - void removeLastOpenTag() { - openTags.remove(); - } - - Deque getOpenTags() { - return openTags; - } -} diff --git a/src/main/java/org/sonarlint/cli/report/source/DecorationDataHolder.java b/src/main/java/org/sonarlint/cli/report/source/DecorationDataHolder.java deleted file mode 100644 index fcdeb73..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/DecorationDataHolder.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report.source; - -import com.google.common.collect.Lists; -import java.util.Iterator; -import java.util.List; -import org.sonarlint.cli.report.RichIssue; - -class DecorationDataHolder { - - private List openingTagsEntries; - private int openingTagsIndex; - private List closingTagsOffsets; - private int closingTagsIndex; - - DecorationDataHolder() { - openingTagsEntries = Lists.newArrayList(); - closingTagsOffsets = Lists.newArrayList(); - } - - void loadIssues(List issues, int currentLineIdx, int currentLineLength) { - for (RichIssue issue : issues) { - int startOffset = issue.getStartLine() == currentLineIdx && issue.getStartLineOffset() != null ? issue.getStartLineOffset() : 0; - int endOffset = issue.getEndLine() == currentLineIdx && issue.getEndLineOffset() != null ? issue.getEndLineOffset() : currentLineLength; - if (startOffset < endOffset) { - insertAndPreserveOrder(new OpeningHtmlTag(startOffset, "issue-" + issue.id()), openingTagsEntries); - insertAndPreserveOrder(endOffset, closingTagsOffsets); - } - } - } - - OpeningHtmlTag getCurrentOpeningTagEntry() { - return openingTagsIndex < openingTagsEntries.size() ? openingTagsEntries.get(openingTagsIndex) : null; - } - - void nextOpeningTagEntry() { - openingTagsIndex++; - } - - int getCurrentClosingTagOffset() { - return closingTagsIndex < closingTagsOffsets.size() ? closingTagsOffsets.get(closingTagsIndex) : -1; - } - - void nextClosingTagOffset() { - closingTagsIndex++; - } - - private static void insertAndPreserveOrder(OpeningHtmlTag newEntry, List openingHtmlTags) { - int insertionIndex = 0; - Iterator tagIterator = openingHtmlTags.iterator(); - while (tagIterator.hasNext() && tagIterator.next().getStartOffset() <= newEntry.getStartOffset()) { - insertionIndex++; - } - openingHtmlTags.add(insertionIndex, newEntry); - } - - private static void insertAndPreserveOrder(int newOffset, List orderedOffsets) { - int insertionIndex = 0; - Iterator entriesIterator = orderedOffsets.iterator(); - while (entriesIterator.hasNext() && entriesIterator.next() <= newOffset) { - insertionIndex++; - } - orderedOffsets.add(insertionIndex, newOffset); - } -} diff --git a/src/main/java/org/sonarlint/cli/report/source/HtmlSourceDecorator.java b/src/main/java/org/sonarlint/cli/report/source/HtmlSourceDecorator.java deleted file mode 100644 index 852e0ee..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/HtmlSourceDecorator.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report.source; - -import java.util.List; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonarlint.cli.report.RichIssue; - -public class HtmlSourceDecorator { - - private HtmlSourceDecorator() { - // utility class, forbidden constructor - } - - @CheckForNull - public static String getDecoratedSourceAsHtml(@Nullable String sourceLine, int currentLineIdx, List issues) { - if (sourceLine == null) { - return null; - } - DecorationDataHolder decorationDataHolder = new DecorationDataHolder(); - decorationDataHolder.loadIssues(issues, currentLineIdx, sourceLine.length()); - HtmlTextDecorator textDecorator = new HtmlTextDecorator(); - return textDecorator.decorateLineWithHtml(sourceLine, decorationDataHolder); - } - -} diff --git a/src/main/java/org/sonarlint/cli/report/source/HtmlTextDecorator.java b/src/main/java/org/sonarlint/cli/report/source/HtmlTextDecorator.java deleted file mode 100644 index f907045..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/HtmlTextDecorator.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report.source; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.util.Collection; - -import static com.google.common.collect.Lists.newArrayList; - -class HtmlTextDecorator { - - static final char HTML_OPENING = '<'; - static final char HTML_CLOSING = '>'; - static final char AMPERSAND = '&'; - static final String ENCODED_HTML_OPENING = "<"; - static final String ENCODED_HTML_CLOSING = ">"; - static final String ENCODED_AMPERSAND = "&"; - - String decorateLineWithHtml(String line, DecorationDataHolder decorationDataHolder) { - - StringBuilder currentHtmlLine = new StringBuilder(); - - BufferedReader stringBuffer = new BufferedReader(new StringReader(line)); - - CharactersReader charsReader = new CharactersReader(stringBuffer); - - try { - while (charsReader.readNextChar()) { - addCharToCurrentLine(charsReader, currentHtmlLine, decorationDataHolder); - } - } catch (IOException e) { - throw new IllegalStateException("Error when decorating source", e); - } - - closeCurrentSyntaxTags(charsReader, currentHtmlLine); - - return currentHtmlLine.toString(); - - } - - private static void addCharToCurrentLine(CharactersReader charsReader, StringBuilder currentHtmlLine, DecorationDataHolder decorationDataHolder) { - int numberOfTagsToClose = getNumberOfTagsToClose(charsReader.getCurrentIndex(), decorationDataHolder); - closeCompletedTags(charsReader, numberOfTagsToClose, currentHtmlLine); - - Collection tagsToOpen = getTagsToOpen(charsReader.getCurrentIndex(), decorationDataHolder); - openNewTags(charsReader, tagsToOpen, currentHtmlLine); - - char currentChar = (char) charsReader.getCurrentValue(); - currentHtmlLine.append(normalize(currentChar)); - } - - private static char[] normalize(char currentChar) { - char[] normalizedChars; - if (currentChar == HTML_OPENING) { - normalizedChars = ENCODED_HTML_OPENING.toCharArray(); - } else if (currentChar == HTML_CLOSING) { - normalizedChars = ENCODED_HTML_CLOSING.toCharArray(); - } else if (currentChar == AMPERSAND) { - normalizedChars = ENCODED_AMPERSAND.toCharArray(); - } else { - normalizedChars = new char[] {currentChar}; - } - return normalizedChars; - } - - private static int getNumberOfTagsToClose(int currentIndex, DecorationDataHolder dataHolder) { - int numberOfTagsToClose = 0; - - while (currentIndex == dataHolder.getCurrentClosingTagOffset()) { - numberOfTagsToClose++; - dataHolder.nextClosingTagOffset(); - } - return numberOfTagsToClose; - } - - private static Collection getTagsToOpen(int currentIndex, DecorationDataHolder dataHolder) { - Collection tagsToOpen = newArrayList(); - while (dataHolder.getCurrentOpeningTagEntry() != null && currentIndex == dataHolder.getCurrentOpeningTagEntry().getStartOffset()) { - tagsToOpen.add(dataHolder.getCurrentOpeningTagEntry().getCssClass()); - dataHolder.nextOpeningTagEntry(); - } - return tagsToOpen; - } - - private static void closeCompletedTags(CharactersReader charactersReader, int numberOfTagsToClose, - StringBuilder decoratedText) { - for (int i = 0; i < numberOfTagsToClose; i++) { - injectClosingHtml(decoratedText); - charactersReader.removeLastOpenTag(); - } - } - - private static void openNewTags(CharactersReader charactersReader, Collection tagsToOpen, - StringBuilder decoratedText) { - for (String tagToOpen : tagsToOpen) { - injectOpeningHtmlForRule(tagToOpen, decoratedText); - charactersReader.registerOpenTag(tagToOpen); - } - } - - private static void closeCurrentSyntaxTags(CharactersReader charactersReader, StringBuilder decoratedText) { - for (int i = 0; i < charactersReader.getOpenTags().size(); i++) { - injectClosingHtml(decoratedText); - } - } - - private static void injectOpeningHtmlForRule(String textType, StringBuilder decoratedText) { - decoratedText.append(""); - } - - private static void injectClosingHtml(StringBuilder decoratedText) { - decoratedText.append(""); - } -} diff --git a/src/main/java/org/sonarlint/cli/report/source/OpeningHtmlTag.java b/src/main/java/org/sonarlint/cli/report/source/OpeningHtmlTag.java deleted file mode 100644 index 13c12d1..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/OpeningHtmlTag.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.report.source; - -class OpeningHtmlTag { - - private final int startOffset; - private final String cssClass; - - OpeningHtmlTag(int startOffset, String cssClass) { - this.startOffset = startOffset; - this.cssClass = cssClass; - } - - int getStartOffset() { - return startOffset; - } - - String getCssClass() { - return cssClass; - } - -} diff --git a/src/main/java/org/sonarlint/cli/report/source/package-info.java b/src/main/java/org/sonarlint/cli/report/source/package-info.java deleted file mode 100644 index 0052819..0000000 --- a/src/main/java/org/sonarlint/cli/report/source/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli.report.source; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/sonarlint/cli/util/HtmlEntities.java b/src/main/java/org/sonarlint/cli/util/HtmlEntities.java deleted file mode 100644 index 218c938..0000000 --- a/src/main/java/org/sonarlint/cli/util/HtmlEntities.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This class offers methods to decode and encode html entities. - * @author Michael Yagudaev - * @version 1.2 April 9, 2011 - */ -public class HtmlEntities { - private static Map map = new LinkedHashMap<>(); - - static { - map.put(""", (char) 34); - map.put("&", (char) 38); - map.put("<", (char) 60); - map.put(">", (char) 62); - map.put(" ", (char) 160); - map.put("¡", (char) 161); - map.put("¢", (char) 162); - map.put("£", (char) 163); - map.put("¤", (char) 164); - map.put("¥", (char) 165); - map.put("¦", (char) 166); - map.put("§", (char) 167); - map.put("¨", (char) 168); - map.put("©", (char) 169); - map.put("ª", (char) 170); - map.put("«", (char) 171); - map.put("¬", (char) 172); - map.put("­", (char) 173); - map.put("®", (char) 174); - map.put("¯", (char) 175); - map.put("°", (char) 176); - map.put("±", (char) 177); - map.put("²", (char) 178); - map.put("³", (char) 179); - map.put("´", (char) 180); - map.put("µ", (char) 181); - map.put("¶", (char) 182); - map.put("·", (char) 183); - map.put("¸", (char) 184); - map.put("¹", (char) 185); - map.put("º", (char) 186); - map.put("»", (char) 187); - map.put("¼", (char) 188); - map.put("½", (char) 189); - map.put("¾", (char) 190); - map.put("¿", (char) 191); - map.put("×", (char) 215); - map.put("÷", (char) 247); - map.put("À", (char) 192); - map.put("Á", (char) 193); - map.put("Â", (char) 194); - map.put("Ã", (char) 195); - map.put("Ä", (char) 196); - map.put("Å", (char) 197); - map.put("Æ", (char) 198); - map.put("Ç", (char) 199); - map.put("È", (char) 200); - map.put("É", (char) 201); - map.put("Ê", (char) 202); - map.put("Ë", (char) 203); - map.put("Ì", (char) 204); - map.put("Í", (char) 205); - map.put("Î", (char) 206); - map.put("Ï", (char) 207); - map.put("Ð", (char) 208); - map.put("Ñ", (char) 209); - map.put("Ò", (char) 210); - map.put("Ó", (char) 211); - map.put("Ô", (char) 212); - map.put("Õ", (char) 213); - map.put("Ö", (char) 214); - map.put("Ø", (char) 216); - map.put("Ù", (char) 217); - map.put("Ú", (char) 218); - map.put("Û", (char) 219); - map.put("Ü", (char) 220); - map.put("Ý", (char) 221); - map.put("Þ", (char) 222); - map.put("ß", (char) 223); - map.put("à", (char) 224); - map.put("á", (char) 225); - map.put("â", (char) 226); - map.put("ã", (char) 227); - map.put("ä", (char) 228); - map.put("å", (char) 229); - map.put("æ", (char) 230); - map.put("ç", (char) 231); - map.put("è", (char) 232); - map.put("é", (char) 233); - map.put("ê", (char) 234); - map.put("ë", (char) 235); - map.put("ì", (char) 236); - map.put("í", (char) 237); - map.put("î", (char) 238); - map.put("ï", (char) 239); - map.put("ð", (char) 240); - map.put("ñ", (char) 241); - map.put("ò", (char) 242); - map.put("ó", (char) 243); - map.put("ô", (char) 244); - map.put("õ", (char) 245); - map.put("ö", (char) 246); - map.put("ø", (char) 248); - map.put("ù", (char) 249); - map.put("ú", (char) 250); - map.put("û", (char) 251); - map.put("ü", (char) 252); - map.put("ý", (char) 253); - map.put("þ", (char) 254); - map.put("ÿ", (char) 255); - } - - private HtmlEntities() { - - } - - /** - * Find the Html Entity and convert it back to a regular character if the - * entity exists, otherwise return the same string. - * @param str - * @return Character represented by HTML Entity or the same string if unknown entity. - */ - private static String fromHtmlEntity(String str) { - Character ch = map.get(str); - return (ch != null) ? ch.toString() : str; - } - - /** - * Finds the value and returns the key that corresponds to that value. If value not found - * returns null. - * @param value The value to be found. - * @return The key corresponding to the value that was found or null if value not found. - */ - private static String findValue(char value) { - Set keySet = map.keySet(); - Iterator i = keySet.iterator(); - String key = i.next(); // key - boolean found = false; - String result = null; - - while (i.hasNext() && !found) { - if (map.get(key).charValue() == value) { - found = true; - result = key; - } - - key = i.next(); - } - - return result; - } - - /** - * Converts special characters in ASCII into html entities (e.g. & -> &) - * @param encode The string to be encoded. - * @return The encoded string with HTML entities. - */ - public static String encode(String encode) { - StringBuilder str = new StringBuilder(encode); - String key; - int i = 0; - - // loop over all the characters in the string - while (i < str.length()) { - // try matching a character to an entity - key = findValue(str.charAt(i)); - if (key != null) { - str.replace(i, i + 1, key); - i += key.length(); - } else { - i++; - } - } - - return str.toString(); - } - - /** - * Converts html entities (e.g. &) into real characters (ASCII characters, e.g. & -> &) - * @param decode A string to be decoded. - * @return The string decoded with no HTML entities. - */ - public static String decode(String decode) { - StringBuilder str = new StringBuilder(decode); - Matcher m = Pattern.compile("&[A-Za-z]+;").matcher(str); - String replaceStr; - - int matchPointer = 0; - while (m.find(matchPointer)) { - // check if we have a corresponding key in our map - replaceStr = fromHtmlEntity(m.group()); - str.replace(m.start(), m.end(), replaceStr); - matchPointer = m.start() + replaceStr.length(); - } - - return str.toString(); - } -} diff --git a/src/main/java/org/sonarlint/cli/util/Logger.java b/src/main/java/org/sonarlint/cli/util/Logger.java deleted file mode 100644 index c1d31a8..0000000 --- a/src/main/java/org/sonarlint/cli/util/Logger.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -import java.io.PrintStream; - -public class Logger { - private static volatile Logger instance; - private boolean debugEnabled = false; - private boolean displayStackTrace = false; - private PrintStream stdOut; - private PrintStream stdErr; - - private Logger() { - this.stdErr = System.err; - this.stdOut = System.out; - } - - public Logger(PrintStream stdOut, PrintStream stdErr) { - this.stdErr = stdErr; - this.stdOut = stdOut; - } - - public static Logger get() { - if (instance == null) { - instance = new Logger(); - } - return instance; - } - - public static void set(PrintStream stdOut, PrintStream stdErr) { - get().stdOut = stdOut; - get().stdErr = stdErr; - } - - public void setDebugEnabled(boolean debugEnabled) { - this.debugEnabled = debugEnabled; - } - - public void setDisplayStackTrace(boolean displayStackTrace) { - this.displayStackTrace = displayStackTrace; - } - - public boolean isDebugEnabled() { - return debugEnabled; - } - - public void debug(String message) { - if (isDebugEnabled()) { - stdErr.println("DEBUG: " + message); - } - } - - public void debug(String message, Throwable t) { - if (isDebugEnabled()) { - stdErr.println("DEBUG: " + message); - if (displayStackTrace) { - t.printStackTrace(stdErr); - } - } - } - - public void info(String message) { - stdErr.println("INFO: " + message); - } - - public void warn(String message) { - stdErr.println("WARN: " + message); - } - - public void error(String message) { - stdErr.println("ERROR: " + message); - } - - public void error(String message, Throwable t) { - stdErr.println("ERROR: " + message); - if (displayStackTrace) { - t.printStackTrace(stdErr); - } - } -} diff --git a/src/main/java/org/sonarlint/cli/util/MutableInt.java b/src/main/java/org/sonarlint/cli/util/MutableInt.java deleted file mode 100644 index 9793cd9..0000000 --- a/src/main/java/org/sonarlint/cli/util/MutableInt.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -public class MutableInt { - private int value; - - public MutableInt() { - this(0); - } - - public MutableInt(int value) { - this.value = value; - } - - public void set(int value) { - this.value = value; - } - - public int get() { - return value; - } - - public void inc() { - value++; - } - - @Override - public int hashCode() { - return value; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - MutableInt other = (MutableInt) obj; - return value == other.value; - } -} diff --git a/src/main/java/org/sonarlint/cli/util/System2.java b/src/main/java/org/sonarlint/cli/util/System2.java deleted file mode 100644 index 287bfb4..0000000 --- a/src/main/java/org/sonarlint/cli/util/System2.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -import javax.annotation.CheckForNull; - -import java.util.Map; -import java.util.Properties; - -/** - * Proxy over {@link java.lang.System}. It aims to improve testability of classes - * that interact with low-level system methods, for example : - *

- *

- * public class MyClass {
- *   private final System2 system;
- *
- *   public MyClass(System2 s) {
- *     this.system = s;
- *   }
- *
- *   public long xxx() {
- *     return system.now();
- *   }
- * }
- *
- * {@literal @}Test
- * public void should_return_xxx() {
- *   // using Mockito
- *   System2 system = mock(System2.class);
- *   long now = 123456789L;
- *   doReturn(now).when(system).now();
- *   assertThat(new MyClass(system).xxx()).isEqualTo(now);
- * }
- * 
- *

- * Note that the name System2 was chosen to not conflict with {@link java.lang.System}. - *

- */ -public class System2 { - - public static final System2 INSTANCE = new System2(); - - /** - * Shortcut for {@link System#currentTimeMillis()} - */ - public long now() { - return System.currentTimeMillis(); - } - - /** - * Shortcut for {@link System#getProperties()} - */ - public Properties properties() { - return System.getProperties(); - } - - /** - * Shortcut for {@link System#getProperty(String)} - */ - @CheckForNull - public String property(String key) { - return System.getProperty(key); - } - - /** - * Shortcut for {@link System#getProperty(String)} - */ - @CheckForNull - public String getProperty(String key) { - return System.getProperty(key); - } - - /** - * Shortcut for {@link System#getenv(String)} - */ - @CheckForNull - public String getenv(String key) { - return System.getenv(key); - } - - public void exit(int code) { - System.exit(code); - } - - /** - * Shortcut for {@link System#getenv()} - */ - public Map envVariables() { - return System.getenv(); - } - - /** - * Shortcut for {@link System#getenv(String)} - */ - @CheckForNull - public String envVariable(String key) { - return System.getenv(key); - } -} diff --git a/src/main/java/org/sonarlint/cli/util/SystemInfo.java b/src/main/java/org/sonarlint/cli/util/SystemInfo.java deleted file mode 100644 index 4964a48..0000000 --- a/src/main/java/org/sonarlint/cli/util/SystemInfo.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -public class SystemInfo { - private static System2 system = new System2(); - - private SystemInfo() { - } - - public static void setSystem(System2 system) { - SystemInfo.system = system; - } - - public static void print(Logger logger) { - logger.info(java()); - logger.info(os()); - String runnerOpts = system.getenv("SONARLINT_OPTS"); - if (runnerOpts != null) { - logger.info("SONARLINT_OPTS=" + runnerOpts); - } - } - - public static String getVersion() { - String version = "unknown"; - - Package p = SystemInfo.class.getPackage(); - if (p != null) { - String implVersion = p.getImplementationVersion(); - if (implVersion != null) { - version = implVersion; - } - } - - return version; - } - - public static String java() { - StringBuilder sb = new StringBuilder(); - sb - .append("Java ") - .append(system.getProperty("java.version")) - .append(" ") - .append(system.getProperty("java.vendor")); - String bits = system.getProperty("sun.arch.data.model"); - if ("32".equals(bits) || "64".equals(bits)) { - sb.append(" (").append(bits).append("-bit)"); - } - return sb.toString(); - } - - public static String os() { - StringBuilder sb = new StringBuilder(); - sb - .append(system.getProperty("os.name")) - .append(" ") - .append(system.getProperty("os.version")) - .append(" ") - .append(system.getProperty("os.arch")); - return sb.toString(); - } -} diff --git a/src/main/java/org/sonarlint/cli/util/Util.java b/src/main/java/org/sonarlint/cli/util/Util.java deleted file mode 100644 index 649f817..0000000 --- a/src/main/java/org/sonarlint/cli/util/Util.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarlint.cli.util; - -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.function.Supplier; - -public class Util { - private Util() { - // static only - } - - public static U getOrCreate(Map map, T key, Supplier f) { - U value = map.get(key); - if (value != null) { - return value; - } - value = f.get(); - map.put(key, value); - return value; - } - - public static Map toMap(Properties properties) { - return new HashMap<>((Map) properties); - } - - public static String escapeFileName(String fileName) { - return fileName.replaceAll("[^a-zA-Z0-9.-]", "_"); - } -} diff --git a/src/main/java/org/sonarlint/cli/util/package-info.java b/src/main/java/org/sonarlint/cli/util/package-info.java deleted file mode 100644 index 463f810..0000000 --- a/src/main/java/org/sonarlint/cli/util/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarLint CLI - * Copyright (C) 2016-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonarlint.cli.util; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/resources/org/sonarlint/cli/report/sonarlintreport.ftl b/src/main/resources/org/sonarlint/cli/report/sonarlintreport.ftl deleted file mode 100644 index 7e01d20..0000000 --- a/src/main/resources/org/sonarlint/cli/report/sonarlintreport.ftl +++ /dev/null @@ -1,349 +0,0 @@ -<#assign component_id_prefix = 'comp'> - - - - - SonarLint report of ${report.getTitle()?html} - - - - - - -

- -
SonarLint Report
-
${report.getTitle()?html} - ${report.getDate()?datetime}
-
- -<#if report.noIssues()> -
- -
-<#else> -
- -
- - - - <#assign size = '33'> - - - -
-

Issues

- <#if report.getSummary().getTotal().getCountInCurrentAnalysis() gt 0> - ${report.getSummary().getTotal().getCountInCurrentAnalysis()?c} - <#else> - 0 - -
-
- - - - - - - - - <#list report.getSummary().getCategoryReports() as categoryReport> - - - - - - - -
- Issues per Rule - Issues
- - - ${categoryReport.getName()?html} - - <#if categoryReport.getTotal().getCountInCurrentAnalysis() gt 0> - ${categoryReport.getTotal().getCountInCurrentAnalysis()?c} - <#else> - 0 - -
-
- -
- - - -
- <#list report.getResourceReports() as resourceReport> - - - - - - - - - <#list resourceReport.getCategoryReports() as categoryReport> - - - - - - - <#assign colspan = '3'> - <#assign issues=resourceReport.getIssuesAtLine(0)> - <#if issues?has_content> - - - - - - - - -
- - - <#if resourceReport.getTotal().getCountInCurrentAnalysis() gt 0> - ${resourceReport.getTotal().getCountInCurrentAnalysis()?c} - <#else> - 0 - -
Issues -
- - - ${categoryReport.getName()?html} - - ${categoryReport.getTotal().getCountInCurrentAnalysis()?c} -
- <#list issues as issue> -
-
- - <#if issue.getMessage()?has_content> - ${issue.getMessage()?html} - <#else> - ${issue.getRuleName()} - -   -   - ${issue.getRuleKey()} -
-
- ${issue.getRuleName()} -
-
- -
- - <#list report.getEscapedSource(resourceReport.getPath()) as line> - <#assign lineIndex=line_index+1> - <#if resourceReport.isDisplayableLine(lineIndex)> - - - - - - - - <#assign issues=resourceReport.getIssuesAtLine(lineIndex)> - <#if issues?has_content> - - - - - - - -
${lineIndex?c} -
${line}
-
- <#list issues as issue> -
-
- - <#if issue.getMessage()?has_content> - ${issue.getMessage()?html} - <#else> - ${issue.getRuleName()} - -   -   - ${issue.getRuleKey()} - <#if issue.creationDate()?has_content> -   -   - ${issue.creationDate()} - -
-
- ${issue.getRuleName()} -
-
- -
-
- -
-
- - - - diff --git a/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/DIR.png b/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/DIR.png deleted file mode 100644 index b135ef92eec475ae36f421425b852ff3eb339b1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 390 zcmV;10eSw3P)D;i>g+kXb7A zAt@;}b=`J;Ib*xx2Z$JSco^n|=b2$(H~?HP^dz%@O_;LtZl5ZMyB2g$u?fzRzWz~; zVhZNooN>G;t83u`ZZk#;{IWmM?$pM>qO8sxMKQm1iJ8p{OnT2TzOFFFHUi*XQk-|m zadUMnNQ{B$ZKoBWH^`R_lyrh(g`iL+rxARX2|h{$*&@Mff#5kukjNTPk{TvFzGOq- z?Ta9iHY~!aZ?*;>bOfp>2_2{L3Ql4bh-azRK!yfhYGUX~uZ#C}@mSSxaHBN^L^(D=@UO?;ZB| klif17bU6Drf8pN)Kje1&o&U^8g8%>k07*qoM6N<$f&iYU3;+NC diff --git a/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/FIL.png b/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/FIL.png deleted file mode 100644 index 1664e25c8b50160089710e75cc105b218bbd1e49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 416 zcmV;R0bl-!P)V{QECN z^Isq*BUP8-56Hm33=G1&%nZ5JM;P&X;V)2Q`SeR*zkm$+55^2&dQzSN1HnK9dAlJ= z8y*fI@B9T4fB!*TM1%qV8ER);2HW@#$@c$1gC-Uj5;g#2OI5r!(BJ>ThW-7EaLFHH zTmVwoI2RTM2-`t)Kd~+-iGhRxJUahD0vDPr2#0~B04qE}fx`ftEg&w!YrvgH4`208 z-SF+px4#U3e*XohL{J#~{sW25kDtH&5fNqjhSPv;3rlrL&CURrVDUeLPi`#$0000< KMNUMnLSTaHU$YSa diff --git a/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/PRJ.png b/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/PRJ.png deleted file mode 100644 index b32e51c5f42a15a7b1223e3b66e53c87cb986e45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 575 zcmV-F0>J%=P)(o*%)Aj(A$XSu?(=)j;T(^uvYF=t2wojnb}Oo0fYIl} zHRDh3FKq|_a5Hq$58(4c--B8Fdn&$m500?CbhjCPHoa)mhIBlQH5Mo3kclqn$l#4i z-|t{W6|S{EBI5{Ki@bbaaWF)DHHQxcUd$QRK1ayJ)5K!yq*v#@{9zypB3V#t^Kn=4 zV#^qBhsL;9OF*^Bp=^@!m%E# z6*s^ISW$W&FA_@{M8R6c=78k!2EgYh#(sZ_sIhBl);M9d~XU-b%)z^?f?o{D>xY`1Xxi{*YBn0!)rv9(Any2 zE0X`*&{2XP!n-o2Uez8V`}N+f=of)*~E zsHF4m3|5rOXZ9hvRMBhz5N&Lz+tt`mS74yGx*jgq?GNlsBr`rE>b>4Sh2+vzpyPb) zzgIcjda68McsV)0EP}rySew(&FPZ-T7V<9=S@B&7^{j668auD6usVgB4NA_=dW4O9BVSq5jcH zUS{Uad%yYEnK!>#hDl+rU=}W9AWvtWox?Dz8HPzuzfk`W^d8XN20AE$#RWZN3S`5j7_2A5z#NRYKK?`s)(f5)|=^iTcyA>k7JEb=mK8IN&2r zBZb^tG5GHaJM1fU!T!!PT$y%9#`T(jbiEuc)+Ah_JJJ2q@mB?QUr1n|35dD3sxqph zz7dD*x_B60ys++SO<+G#1te2j82`t9C%ak|xqA!+ub<4H+UO!`hVS({wSzJ2Rwee4 z_WI(vp!fM*nWfwD+FIRNjixxxQ&ubFet2()YQC|@`RhfIx>PyRpWM5)Pg-c9* zsEl3F>O(b#gr8Gi=B^EhYvyZmj$2c5)|obw<(;r@*8M@}s(QGklldgtMhL@<${^%a zXuTigEJzQ?0gyWxW~7s0hM=sy#4zWn{vSUYXVO6mL1;W0O*HUaPXF2pz_&<&{c*!o z&g5(is#~xv2urAs#+KQ@kB6ylkL+5bf)u zZcHFX7sa!kjrIVnd(_R5h+tbj8~E`sRRJG{d#RJu7hf6AHreg;elgtKAlxrIl8rqT zJWXLYe7iG`05`dp+S9wHLCl>$72jmos3Hz(5__t>IAbow(vTr&EY2!nD;h_(I` zmHeM@=CY_AP>~dPSG1@idvGGZWa*v;cZDvq-vCDrMSy>seFOy@guAfZtj{F>%E{)pdT~crbsjzEub5a(j>0)%2_Fc1 z@EJIV%S?U9!#)LPpp(WyQTPdOh{xOFm=<-!!G+uLqc0)3hwKyf;lVr{ZAYh=SRzi%&DzjuJ4F5d+e;y z^#}f=(>LOD`lRm@_@=8so`yH(e#&F$oFfW%Fd(A4tyq3|w;uCxKej0R$uHlsXIR@b z8SM#5NbPYHUSrjdFVi^DRh6fNBvb=^9#UoYG|YvxZwLM+qqA_AR6!i&t$vLVZ(#q` zz?mm4@V5JW+}jWK`fg1`Cz~Ahu{W62-&%&dX=^v^C0$_qp|9g%H&+j9ToRLUVco{8 zc~;v)WoT6h-it9W-w%7ByQPAE$l6ZlstNYJfb(_4mp3KuLw)=^GgI5-ta?70sk1>_8#lsBBId_CB@Y<Z zhCu$RC1jw9klq49Vx@$<_ZlI~ddbM{FaOI)#n@6wi+9vv)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=lt(),k=lt(),E=lt(),S=!1,A=function(){return 0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=bt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+xt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return At(e.replace(z,"$1"),t,n,i)}function st(e){return K.test(e+"")}function lt(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[b]=!0,e}function ct(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function pt(e,t,n){e=e.split("|");var r,i=e.length,a=n?null:t;while(i--)(r=o.attrHandle[e[i]])&&r!==t||(o.attrHandle[e[i]]=a)}function ft(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function dt(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:t}function gt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function yt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function vt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.parentWindow;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.frameElement&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ct(function(e){return e.innerHTML="
",pt("type|href|height|width",dt,"#"===e.firstChild.getAttribute("href")),pt(B,ft,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),r.input=ct(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),pt("value",ht,r.attributes&&r.input),r.getElementsByTagName=ct(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ct(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ct(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=st(n.querySelectorAll))&&(ct(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ct(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=st(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ct(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=st(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},r.sortDetached=ct(function(e){return 1&e.compareDocumentPosition(n.createElement("div"))}),A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return gt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?gt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:ut,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=bt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?ut(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return at(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:vt(function(){return[0]}),last:vt(function(e,t){return[t-1]}),eq:vt(function(e,t,n){return[0>n?n+t:n]}),even:vt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:vt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:vt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:vt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=mt(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=yt(n);function bt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function wt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function Tt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Ct(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function Nt(e,t,n,r,i,o){return r&&!r[b]&&(r=Nt(r)),i&&!i[b]&&(i=Nt(i,o)),ut(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||St(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:Ct(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=Ct(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=Ct(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function kt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=wt(function(e){return e===t},s,!0),p=wt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[wt(Tt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return Nt(l>1&&Tt(f),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),i>r&&kt(e=e.slice(r)),i>r&&xt(e))}f.push(n)}return Tt(f)}function Et(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=Ct(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?ut(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=bt(e)),n=t.length;while(n--)o=kt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Et(i,r))}return o};function St(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function At(e,t,n,i){var a,s,u,c,p,f=bt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&xt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}o.pseudos.nth=o.pseudos.eq;function jt(){}jt.prototype=o.filters=o.pseudos,o.setFilters=new jt,r.sortStable=b.split("").sort(A).join("")===b,p(),[0,0].sort(A),r.detectDuplicates=S,x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!u||(n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null) -}),n=s=l=u=r=o=null,t}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=x(this),l=t,u=e.match(T)||[];while(o=u[a++])l=r?l:!s.hasClass(o),s[l?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); - u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("