diff --git a/.gitignore b/.gitignore index 6d6a56f8..a680191b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ libs out .DS_Store lib/kotlin-* +build +.history diff --git a/README.md b/README.md index 81d87855..d5d7cbe0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Kobalt -[](https://teamcity.jetbrains.com/project.html?projectId=OpenSourceProjects_Kobalt&tab=projectOverview) +[](https://teamcity.jetbrains.com/project.html?projectId=OpenSourceProjects_Kobalt&tab=projectOverview) Kobalt is a universal build system. @@ -8,7 +8,7 @@ Kobalt is a universal build system. To build it: ``` -./kobaltw assemble +$ ./kobaltw assemble ``` Please see [the web site](http://beust.com/kobalt/) for the full documentation. diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..3f0053cc --- /dev/null +++ b/build.gradle @@ -0,0 +1,58 @@ +allprojects { + group = 'com.beust' + version = '1.1.0' +} + +subprojects { + apply plugin: 'java' + apply plugin: 'maven-publish' + + ext { + bndlib = '3.5.0' + findbugs = '3.0.2' + groovy = '2.4.12' + gson = '2.8.2' + guice = '4.2.2' + inject = '1' + jaxb = '2.3.0' + jcommander = '1.72' + kotlin = '1.2.71' + maven = '3.5.2' + mavenResolver = '1.1.0' + okhttp = '3.9.1' + okio = '1.13.0' + retrofit = '2.3.0' + slf4j = '1.7.3' + spark = '2.6.0' + testng = '6.12' + + junit = '4.12' + junitJupiter = '5.1.0' + junitPlatform = '1.1.0' + } + + repositories { + mavenCentral() + mavenLocal() + jcenter() + maven { + url = 'https://dl.bintray.com/cbeust/maven' + } + + maven { + url = 'https://repo.maven.apache.org/maven2' + } + } + + sourceCompatibility = '1.7' + + task sourcesJar(type: Jar) { + from sourceSets.main.allJava + archiveClassifier = 'sources' + } + + task javadocJar(type: Jar) { + from javadoc + archiveClassifier = 'javadoc' + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..5c2d1cf0 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..838e6bc8 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..b0d6d0ab --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## 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='"-Xmx64m" "-Xms64m"' + +# 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 00000000..9991c503 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@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="-Xmx64m" "-Xms64m" + +@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/kobalt/src/Build.kt b/kobalt/src/Build.kt index 904c428c..0d09844a 100644 --- a/kobalt/src/Build.kt +++ b/kobalt/src/Build.kt @@ -21,26 +21,27 @@ import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream val bs = buildScript { - repos("http://dl.bintray.com/cbeust/maven") + repos("https://dl.bintray.com/cbeust/maven") } object Versions { - val okhttp = "3.2.0" - val okio = "1.6.0" - val retrofit = "2.1.0" - val gson = "2.6.2" - val maven = "3.3.9" - val mavenResolver = "1.0.3" + val kotlin = "1.2.71" + val okhttp = "3.9.1" + val okio = "1.13.0" + val retrofit = "2.3.0" + val gson = "2.8.2" + val guice = "4.2.2" + val maven = "3.5.2" + val mavenResolver = "1.1.0" val slf4j = "1.7.3" - val kotlin = "1.1.2" val aether = "1.0.2.v20150114" - val testng = "6.11" + val testng = "6.12" + val jcommander = "1.72" // JUnit 5 val junit = "4.12" - val junitPlatform = "1.0.0-M4" - val junitJupiter = "5.0.0-M4" - val junitVintageVersion = "$junit.0-M4" + val junitPlatform = "1.1.0" + val junitJupiter = "5.1.0" } fun mavenResolver(vararg m: String) @@ -78,6 +79,7 @@ val wrapper = project { bintray { publish = true + sign = true } pom = createPom(name, "Wrapper for Kobalt") @@ -90,41 +92,42 @@ val kobaltPluginApi = project { version = readVersion() directory = "modules/kobalt-plugin-api" description = "A build system in Kotlin" - url = "http://beust.com/kobalt" + url = "https://beust.com/kobalt" pom = createPom(name, "A build system in Kotlin") dependencies { compile( "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}", - "com.google.inject:guice:4.0", - "com.google.inject.extensions:guice-assistedinject:4.0", + "com.google.inject:guice:${Versions.guice}", + "com.google.inject.extensions:guice-assistedinject:4.1.0", "javax.inject:javax.inject:1", - "com.google.guava:guava:21.0", + "com.google.guava:guava:27.0.1-jre", "org.apache.maven:maven-model:${Versions.maven}", - "io.reactivex:rxjava:1.1.5", + "io.reactivex:rxjava:1.3.3", "com.squareup.okio:okio:${Versions.okio}", "com.google.code.gson:gson:${Versions.gson}", "com.squareup.okhttp3:okhttp:${Versions.okhttp}", "com.squareup.retrofit2:retrofit:${Versions.retrofit}", "com.squareup.retrofit2:converter-gson:${Versions.retrofit}", - "com.beust:jcommander:1.48", - "org.eclipse.jgit:org.eclipse.jgit:4.5.0.201609210915-r", + "com.beust:jcommander:${Versions.jcommander}", + "org.eclipse.jgit:org.eclipse.jgit:4.9.0.201710071750-r", "org.slf4j:slf4j-simple:${Versions.slf4j}", *mavenResolver("api", "spi", "util", "impl", "connector-basic", "transport-http", "transport-file"), "org.apache.maven:maven-aether-provider:3.3.9", "org.testng.testng-remote:testng-remote:1.3.2", "org.testng:testng:${Versions.testng}", - "commons-io:commons-io:2.5", "org.junit.platform:junit-platform-surefire-provider:${Versions.junitPlatform}", "org.junit.platform:junit-platform-runner:${Versions.junitPlatform}", "org.junit.platform:junit-platform-engine:${Versions.junitPlatform}", "org.junit.platform:junit-platform-console:${Versions.junitPlatform}", "org.junit.jupiter:junit-jupiter-engine:${Versions.junitJupiter}", - "org.junit.vintage:junit-vintage-engine:${Versions.junitVintageVersion}", + "org.junit.vintage:junit-vintage-engine:${Versions.junitJupiter}", + "org.apache.commons:commons-compress:1.15", + "commons-io:commons-io:2.6", - "org.apache.commons:commons-compress:1.13", - "commons-io:commons-io:2.5" + // Java 9 + "javax.xml.bind:jaxb-api:2.3.0" ) exclude(*aether("impl", "spi", "util", "api")) } @@ -161,24 +164,30 @@ val kobaltApp = project(kobaltPluginApi, wrapper) { // Used by the main app compile( "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}", - "com.github.spullara.mustache.java:compiler:0.9.1", + "com.github.spullara.mustache.java:compiler:0.9.5", "javax.inject:javax.inject:1", - "com.google.inject:guice:4.0", - "com.google.inject.extensions:guice-assistedinject:4.0", - "com.beust:jcommander:1.65", + "com.google.inject:guice:${Versions.guice}", + "com.google.inject.extensions:guice-assistedinject:${Versions.guice}", + "com.beust:jcommander:${Versions.jcommander}", "org.apache.maven:maven-model:${Versions.maven}", - "com.google.code.findbugs:jsr305:3.0.1", + "com.google.code.findbugs:jsr305:3.0.2", "com.google.code.gson:gson:${Versions.gson}", "com.squareup.retrofit2:retrofit:${Versions.retrofit}", "com.squareup.retrofit2:converter-gson:${Versions.retrofit}", - "com.squareup.okhttp3:okhttp-ws:${Versions.okhttp}", - "biz.aQute.bnd:bndlib:2.4.0", +// "com.squareup.okhttp3:okhttp-ws:3.4.2", + "biz.aQute.bnd:biz.aQute.bndlib:3.5.0", *mavenResolver("spi"), - "com.squareup.okhttp3:logging-interceptor:3.2.0", + "com.squareup.okhttp3:logging-interceptor:3.9.0", - "com.sparkjava:spark-core:2.5", - "org.codehaus.groovy:groovy:2.4.8" + "com.sparkjava:spark-core:2.6.0", + "org.codehaus.groovy:groovy:2.4.12", + + // Java 9 + "javax.xml.bind:jaxb-api:2.3.0", + "com.sun.xml.bind:jaxb-impl:2.3.0", + "com.sun.xml.bind:jaxb-core:2.3.0", + "com.sun.activation:javax.activation:1.2.0" // "org.eclipse.jetty:jetty-server:${Versions.jetty}", // "org.eclipse.jetty:jetty-servlet:${Versions.jetty}", @@ -194,7 +203,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) { dependenciesTest { compile("org.jetbrains.kotlin:kotlin-test:${Versions.kotlin}", "org.testng:testng:${Versions.testng}", - "org.assertj:assertj-core:3.4.1", + "org.assertj:assertj-core:3.8.0", *mavenResolver("util") ) } @@ -300,13 +309,13 @@ fun taskCopyVersionForWrapper(project: Project) : TaskResult { fun createPom(projectName: String, projectDescription: String) = Model().apply { name = projectName description = projectDescription - url = "http://beust.com/kobalt" + url = "https://beust.com/kobalt" licenses = listOf(License().apply { name = "Apache-2.0" - url = "http://www.apache.org/licenses/LICENSE-2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0" }) scm = Scm().apply { - url = "http://github.com/cbeust/kobalt" + url = "https://github.com/cbeust/kobalt" connection = "https://github.com/cbeust/kobalt.git" developerConnection = "git@github.com:cbeust/kobalt.git" } @@ -314,4 +323,4 @@ fun createPom(projectName: String, projectDescription: String) = Model().apply { name = "Cedric Beust" email = "cedric@beust.com" }) -} \ No newline at end of file +} diff --git a/kobalt/wrapper/kobalt-wrapper.properties b/kobalt/wrapper/kobalt-wrapper.properties index ab35bea5..0ca8045f 100644 --- a/kobalt/wrapper/kobalt-wrapper.properties +++ b/kobalt/wrapper/kobalt-wrapper.properties @@ -1 +1 @@ -kobalt.version=1.0.79 \ No newline at end of file +kobalt.version=1.0.122 \ No newline at end of file diff --git a/kobaltw-test b/kobaltw-test new file mode 100755 index 00000000..2693c3aa --- /dev/null +++ b/kobaltw-test @@ -0,0 +1,8 @@ +#!/usr/bin/env sh +JAR=$(ls -1 -t kobaltBuild/libs/*.jar | grep -Ev "(sources|javadoc)" | head -1) +TEMPDIR=$(mktemp -d) +cp -pf "$JAR" "$TEMPDIR" +TEMPJAR=$TEMPDIR/$(basename "$JAR") +export KOBALT_JAR=$TEMPJAR +java -jar "$TEMPJAR" "$@" +rm -rf "$TEMPDIR" \ No newline at end of file diff --git a/modules/kobalt-plugin-api/build.gradle b/modules/kobalt-plugin-api/build.gradle new file mode 100644 index 00000000..56085220 --- /dev/null +++ b/modules/kobalt-plugin-api/build.gradle @@ -0,0 +1,85 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.2.71' + id 'com.github.johnrengelman.shadow' version '5.0.0' +} + +dependencies { + implementation "biz.aQute.bnd:biz.aQute.bndlib:$bndlib" + implementation "com.google.code.findbugs:jsr305:$findbugs" + implementation "com.sparkjava:spark-core:$spark" + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp" + implementation 'commons-io:commons-io:2.6' + implementation 'io.reactivex:rxjava:1.3.3' + implementation "javax.inject:javax.inject:$inject" + implementation "javax.xml.bind:jaxb-api:$jaxb" + implementation 'org.apache.commons:commons-compress:1.15' + implementation 'org.apache.maven:maven-aether-provider:3.3.9' + implementation "org.apache.maven.resolver:maven-resolver-api:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-connector-basic:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-impl:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-spi:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-transport-file:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-transport-http:$mavenResolver" + implementation "org.apache.maven.resolver:maven-resolver-util:$mavenResolver" + implementation "org.codehaus.groovy:groovy:$groovy" + implementation 'org.eclipse.jgit:org.eclipse.jgit:4.9.0.201710071750-r' + implementation "org.junit.jupiter:junit-jupiter-engine:$junitJupiter" + implementation "org.junit.platform:junit-platform-console:$junitPlatform" + implementation "org.junit.platform:junit-platform-engine:$junitPlatform" + implementation "org.junit.platform:junit-platform-runner:$junitPlatform" + implementation "org.junit.platform:junit-platform-surefire-provider:$junitPlatform" + implementation "org.junit.vintage:junit-vintage-engine:$junitJupiter" + implementation "org.slf4j:slf4j-simple:$slf4j" + implementation "org.testng:testng:$testng" + implementation 'org.testng.testng-remote:testng-remote:1.3.2' + implementation "com.beust:jcommander:$jcommander" + implementation "com.google.code.gson:gson:$gson" + implementation "com.google.inject:guice:$guice" + implementation "com.google.inject.extensions:guice-assistedinject:$guice" + implementation "com.squareup.okio:okio:$okio" + implementation "com.squareup.retrofit2:converter-gson:$retrofit" + implementation "com.squareup.retrofit2:retrofit:$retrofit" + implementation "org.apache.maven:maven-model:$maven" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin" +} + +shadowJar { + classifier = null +} + +test { + useTestNG() +} + +publishing { + publications { + shadow(MavenPublication) { publication -> + project.shadow.component(publication) + artifact sourcesJar + artifact javadocJar + + pom { + name = project.name + description = 'A build system in Kotlin' + url = 'https://beust.com/kobalt' + licenses { + license { + name = 'Apache-2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0' + } + } + developers { + developer { + name = 'Cedric Beust' + email = 'cedric@beust.com' + } + } + scm { + connection = 'scm:https://github.com/cbeust/kobalt.git' + developerConnection = 'scm:git@github.com:cbeust/kobalt.git' + url = 'https://github.com/cbeust/kobalt' + } + } + } + } +} diff --git a/modules/kobalt-plugin-api/pom.xml b/modules/kobalt-plugin-api/pom.xml new file mode 100644 index 00000000..f9026387 --- /dev/null +++ b/modules/kobalt-plugin-api/pom.xml @@ -0,0 +1,279 @@ + + 4.0.0 + + com.beust + kobalt-pom + 1.1.0 + ../.. + + + kobalt-plugin-api + jar + 1.1.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + org.apache.maven + maven-aether-provider + 3.3.9 + + + org.eclipse.aether + impl + + + org.eclipse.aether + spi + + + org.eclipse.aether + util + + + org.eclipse.aether + api + + + + + org.apache.maven.resolver + maven-resolver-api + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-spi + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-util + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-impl + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-connector-basic + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-http + ${mavenresolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-file + ${mavenresolver.version} + + + io.reactivex + rxjava + 1.3.3 + + + com.squareup.okio + okio + ${okio.version} + + + javax.inject + javax.inject + 1 + compile + + + com.google.inject + guice + 4.2.2 + + + com.google.inject.extensions + guice-assistedinject + 4.2.2 + + + com.beust + jcommander + 1.72 + + + org.apache.maven + maven-model + 3.5.2 + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + com.google.code.gson + gson + 2.8.2 + + + com.squareup.retrofit2 + retrofit + 2.3.0 + + + com.squareup.retrofit2 + converter-gson + 2.3.0 + + + biz.aQute.bnd + biz.aQute.bndlib + 3.5.0 + + + com.squareup.okhttp3 + logging-interceptor + ${okhttp3.version} + + + com.sparkjava + spark-core + 2.6.0 + + + org.codehaus.groovy + groovy + 2.4.12 + + + org.apache.commons + commons-compress + 1.15 + + + commons-io + commons-io + 2.6 + + + org.junit.platform + junit-platform-surefire-provider + ${junit.version} + + + org.junit.platform + junit-platform-runner + ${junit.version} + + + org.junit.platform + junit-platform-engine + ${junit.version} + + + org.junit.platform + junit-platform-console + ${junit.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junitJupiter.version} + + + org.junit.vintage + junit-vintage-engine + ${junitJupiter.version} + + + org.testng.testng-remote + testng-remote + 1.3.2 + + + org.testng + testng + ${testng.version} + + + org.eclipse.jgit + org.eclipse.jgit + 4.9.0.201710071750-r + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + + ${project.basedir}/src/main/kotlin + + + + + test-compile + test-compile + + + ${project.basedir}/src/test/kotlin + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + compile + + + java-test-compile + test-compile + testCompile + + + + + + \ No newline at end of file diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt index b8cdc2fe..372f1ba1 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt @@ -61,6 +61,9 @@ class Args { @Parameter(names = arrayOf("--noIncremental"), description = "Turn off incremental builds") var noIncremental: Boolean = false + @Parameter(names = arrayOf("--offline"), description = "Don't try to download dependencies even if there is no cached version") + var offline: Boolean = false + @Parameter(names = arrayOf("--plugins"), description = "Comma-separated list of plug-in Maven id's") var pluginIds: String? = null @@ -101,5 +104,8 @@ class Args { @Parameter(names = arrayOf("--update"), description = "Update to the latest version of Kobalt") var update: Boolean = false + + @Parameter(names = arrayOf("--version"), description = "Display the current version of Kobalt") + var version: Boolean = false } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt index e7a6c3dd..8eb73c84 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt @@ -9,13 +9,13 @@ object Constants { val BUILD_FILE_NAME = "Build.kt" val BUILD_FILE_DIRECTORY = "kobalt/src" val BUILD_FILE_PATH = KFiles.joinDir(BUILD_FILE_DIRECTORY, BUILD_FILE_NAME) - val KOTLIN_COMPILER_VERSION = "1.1.2" + val KOTLIN_COMPILER_VERSION = "1.2.70" internal val DEFAULT_REPOS = listOf( // "https://maven-central.storage.googleapis.com/", - HostConfig("http://repo1.maven.org/maven2/", "Maven"), + HostConfig("https://repo1.maven.org/maven2/", "Maven"), HostConfig("https://jcenter.bintray.com/", "JCenter") -// "http://repository.jetbrains.com/all/", // <-- contains snapshots +// "https://repository.jetbrains.com/all/", // <-- contains snapshots // snapshots // "https://oss.sonatype.org/content/repositories/snapshots/" diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Jvm.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Jvm.kt index 598ca401..14c55efd 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Jvm.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Jvm.kt @@ -67,7 +67,7 @@ open class Jvm constructor( return toolsJar } if (javaHome!!.name.equals("jre", true)) { - javaHome = javaHome!!.parentFile + _javaHome = javaHome!!.parentFile toolsJar = File(javaHome, "lib/tools.jar") if (toolsJar.exists()) { return toolsJar @@ -78,7 +78,7 @@ open class Jvm constructor( val version = SystemProperties.Companion.javaVersion if (javaHome!!.name.toRegex().matches("jre\\d+") || javaHome!!.name == "jre$version") { - javaHome = File(javaHome!!.parentFile, "jdk$version") + _javaHome = File(javaHome!!.parentFile, "jdk$version") toolsJar = File(javaHome, "lib/tools.jar") if (toolsJar.exists()) { return toolsJar diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Variant.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Variant.kt index d15327b1..13120fa0 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Variant.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Variant.kt @@ -126,61 +126,62 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null, var generatedSourceDirectory: File? = null -// private fun findBuildTypeBuildConfig(project: Project, variant: Variant?) : BuildConfig? { -// val buildTypeName = variant?.buildType?.name -// return project.buildTypes[buildTypeName]?.buildConfig -// } -// -// private fun findProductFlavorBuildConfig(project: Project, variant: Variant?) : BuildConfig? { -// val buildTypeName = variant?.productFlavor?.name -// return project.productFlavors[buildTypeName]?.buildConfig -// } + private fun findBuildTypeBuildConfig(project: Project, variant: Variant?) : BuildConfig? { + val buildTypeName = variant?.buildType?.name + return project.buildTypes[buildTypeName]?.buildConfig + } + + private fun findProductFlavorBuildConfig(project: Project, variant: Variant?) : BuildConfig? { + val buildTypeName = variant?.productFlavor?.name + return project.productFlavors[buildTypeName]?.buildConfig + } /** * Return a list of the BuildConfigs found on the productFlavor{}, buildType{} and project{} (in that order). */ -// private fun findBuildConfigs(project: Project, variant: Variant?) : List { -// val result = listOf( -// findBuildTypeBuildConfig(project, variant), -// findProductFlavorBuildConfig(project, variant), -// project.buildConfig) -// .filterNotNull() -// -// return result -// } + private fun findBuildConfigs(project: Project, variant: Variant?) : List { + val result = listOf( + findBuildTypeBuildConfig(project, variant), + findProductFlavorBuildConfig(project, variant), + project.buildConfig) + .filterNotNull() + + return result + } /** * Generate BuildConfig.java if requested. Also look up if any BuildConfig is defined on the current build type, * product flavor or main project, and use them to generateAndSave any additional field (in that order to * respect the priorities). Return the generated file if it was generated, null otherwise. */ -// fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) : File? { -// val buildConfigs = findBuildConfigs(project, this) -// -// if (buildConfigs.size > 0) { -// val pkg = project.packageName ?: project.group -// ?: throw KobaltException( -// "packageName needs to be defined on the project in order to generateAndSave BuildConfig") -// -// val contributor = ActorUtils.selectAffinityActor(context.pluginInfo.buildConfigContributors, project) -// if (contributor != null) { -// val code = contributor.generateBuildConfig(project, context, pkg, this, buildConfigs) -// val result = KFiles.makeDir(KFiles.generatedSourceDir(project, this, "buildConfig")) -// // Make sure the generatedSourceDirectory doesn't contain the project.directory since -// // that directory will be added when trying to find recursively all the sources in it -// generatedSourceDirectory = result.relativeTo(File(project.directory)) -// val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar)) -// val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig." + contributor.buildConfigSuffix) -// KFiles.saveFile(outputDir, code) -// context.logger.log(project.name, 2, "Generated ${outputDir.path}") -// return result -// } else { -// throw KobaltException("Couldn't find a contributor to generateAndSave BuildConfig") -// } -// } else { -// return null -// } -// } + fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) : File? { + val buildConfigs = findBuildConfigs(project, this) + + if (buildConfigs.size > 0) { + val pkg = project.packageName ?: project.group + ?: throw KobaltException( + "packageName needs to be defined on the project in order to generateAndSave BuildConfig") + + val contributor = ActorUtils.selectAffinityActor(project, context, + context.pluginInfo.buildConfigContributors) + if (contributor != null) { + val code = contributor.generateBuildConfig(project, context, pkg, this, buildConfigs) + val result = KFiles.makeDir(KFiles.generatedSourceDir(project, this, "buildConfig")) + // Make sure the generatedSourceDirectory doesn't contain the project.directory since + // that directory will be added when trying to find recursively all the sources in it + generatedSourceDirectory = result.relativeTo(File(project.directory)) + val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar)) + val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig." + contributor.buildConfigSuffix) + KFiles.saveFile(outputDir, code) + context.logger.log(project.name, 2, "Generated ${outputDir.path}") + return result + } else { + throw KobaltException("Couldn't find a contributor to generateAndSave BuildConfig") + } + } else { + return null + } + } override fun toString() = toTask("") diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IBuildConfigContributor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IBuildConfigContributor.kt index 35553f74..ef9d3b4d 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IBuildConfigContributor.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IBuildConfigContributor.kt @@ -5,7 +5,7 @@ import com.beust.kobalt.Variant /** * Plug-ins that can generate a BuildConfig file. */ -interface IBuildConfigContributor : ISimpleAffinity { +interface IBuildConfigContributor : IProjectAffinity { fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant, buildConfigs: List) : String diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt index f8bd656c..5334e09f 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt @@ -17,7 +17,8 @@ class Archives { @ExportedProjectProperty(doc = "The name of the a jar file with a main() method", type = "String") const val JAR_NAME_WITH_MAIN_CLASS = "jarNameWithMainClass" - fun defaultArchiveName(project: Project) = project.name + "-" + project.version + fun defaultArchiveName(project: Project) = project.name + + if (project.version.isNullOrBlank()) "" else "-${project.version}" fun generateArchive(project: Project, context: KobaltContext, diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/MetaArchive.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/MetaArchive.kt index ddb1e727..c217c83e 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/MetaArchive.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/MetaArchive.kt @@ -9,7 +9,6 @@ import java.io.Closeable import java.io.File import java.io.FileInputStream import java.io.FileOutputStream -import java.nio.file.Files import java.util.jar.Manifest import org.apache.commons.compress.archivers.zip.ZipFile as ApacheZipFile @@ -19,18 +18,39 @@ import org.apache.commons.compress.archivers.zip.ZipFile as ApacheZipFile */ class MetaArchive(outputFile: File, val manifest: Manifest?) : Closeable { companion object { - val MANIFEST_MF = "META-INF/MANIFEST.MF" + const val MANIFEST_MF = "META-INF/MANIFEST.MF" } - private val zos = ZipArchiveOutputStream(outputFile).apply { + private val zos= ZipArchiveOutputStream(outputFile).apply { encoding = "UTF-8" } + init { + // If no manifest was passed, create an empty one so it's the first one in the archive + val m = manifest ?: Manifest() + val manifestFile = File.createTempFile("kobalt", "tmpManifest") + addEntry(ZipArchiveEntry("META-INF/"), null) + if (manifest != null) { + FileOutputStream(manifestFile).use { fos -> + m.write(fos) + } + } + val entry = zos.createArchiveEntry(manifestFile, MetaArchive.MANIFEST_MF) + addEntry(entry, FileInputStream(manifestFile)) + } + + fun addFile(f: File, entryFile: File, path: String?) { + maybeCreateParentDirectories(f) + addFile2(f, entryFile, path) + } + + private fun addFile2(f: File, entryFile: File, path: String?) { val file = f.normalize() FileInputStream(file).use { inputStream -> val actualPath = KFiles.fixSlashes(if (path != null) path + entryFile.path else entryFile.path) ZipArchiveEntry(actualPath).let { entry -> + maybeCreateParentDirectories(File(actualPath)) maybeAddEntry(entry) { addEntry(entry, inputStream) } @@ -38,6 +58,30 @@ class MetaArchive(outputFile: File, val manifest: Manifest?) : Closeable { } } + private val createdDirs = hashSetOf() + + /** + * For an entry a/b/c/File, an entry needs to be created for each individual directory: + * a/ + * a/b/ + * a/b/c + * a/b/c/File + */ + private fun maybeCreateParentDirectories(file: File) { + val toCreate = arrayListOf() + var current = file.parentFile + while (current != null && current.path != ".") { + if (!createdDirs.contains(current.path)) { + toCreate.add(0, KFiles.fixSlashes(current) + "/") + createdDirs.add(current.path) + } + current = current.parentFile + } + toCreate.forEach { dir -> + addEntry(ZipArchiveEntry(dir), null) + } + } + fun addArchive(jarFile: File) { ApacheZipFile(jarFile).use { jar -> val jarEntries = jar.entries @@ -49,40 +93,33 @@ class MetaArchive(outputFile: File, val manifest: Manifest?) : Closeable { } } - private val DEFAULT_JAR_EXCLUDES = - Glob("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA") - private val seen = hashSetOf() - private fun okToAdd(name: String): Boolean = ! seen.contains(name) - && ! KFiles.isExcluded(name, DEFAULT_JAR_EXCLUDES) - - override fun close() { - if (manifest != null) { - Files.createTempFile("aaa", "bbb").toFile().let { manifestFile -> - FileOutputStream(manifestFile).use { fos -> - manifest.write(fos) - } - - val entry = zos.createArchiveEntry(manifestFile, MetaArchive.MANIFEST_MF) - addEntry(entry, FileInputStream(manifestFile)) - } - } - zos.close() + private fun okToAdd(name: String) : Boolean { + val result = !KFiles.isExcluded(name, + Glob("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", MANIFEST_MF)) +// if (name.startsWith("META-INF")) println((if (result) "ADDING" else "NOT ADDING") + " $name") + return result } - private fun addEntry(entry: ArchiveEntry, inputStream: FileInputStream) { + override fun close() = zos.close() + + private fun addEntry(entry: ArchiveEntry, inputStream: FileInputStream?) { zos.putArchiveEntry(entry) - inputStream.use { ins -> + inputStream?.use { ins -> ins.copyTo(zos, 50 * 1024) } zos.closeArchiveEntry() } + private val seen = hashSetOf() + private fun maybeAddEntry(entry: ArchiveEntry, action:() -> Unit) { - if (okToAdd(entry.name)) { - action() + entry.name.let { name -> + if (!seen.contains(name) && okToAdd(name)) { + action() + } + seen.add(name) } - seen.add(entry.name) } } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/DocUrl.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/DocUrl.kt index 8acab0ab..93010294 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/DocUrl.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/DocUrl.kt @@ -2,7 +2,7 @@ package com.beust.kobalt.internal class DocUrl { companion object { - private const val HOST = "http://beust.com/kobalt/" + private const val HOST = "https://beust.com/kobalt/" private fun url(path: String) = HOST + path val PUBLISH_PLUGIN_URL = url("plug-ins/index.html#publishing") diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt index fb2b0927..995dba53 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt @@ -112,10 +112,11 @@ abstract class GenericTestRunner: ITestRunnerContributor { configName: String) : TestResult { var result = false - context.logger.log(project.name, 1, "Running tests with " + runnerName) + context.logger.log(project.name, 1, "Running tests with $runnerName") val testConfig = project.testConfigs.firstOrNull { it.name == configName } + var errorCode = -1 if (testConfig != null) { val args = args(project, context, classpath, testConfig) if (args.size > 0) { @@ -136,12 +137,7 @@ abstract class GenericTestRunner: ITestRunnerContributor { context.logger.log(project.name, 2, "Running tests with classpath size ${classpath.size}") context.logger.log(project.name, 2, "Launching " + allArgs.joinToString(" ")) val process = pb.start() - val errorCode = process.waitFor() - if (errorCode == 0) { - context.logger.log(project.name, 1, "All tests passed") - } else { - context.logger.log(project.name, 1, "Test failures") - } + errorCode = process.waitFor() result = result || errorCode == 0 } else { context.logger.log(project.name, 1, " No tests to run") @@ -152,6 +148,13 @@ abstract class GenericTestRunner: ITestRunnerContributor { } onFinish(project) + + if (errorCode == 0) { + context.logger.log(project.name, 1, "All tests passed") + } else { + context.logger.log(project.name, 1, longMessage!!) + } + return TestResult(result, shortMessage, longMessage) } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JUnit5Runner.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JUnit5Runner.kt index 7dd72df7..2e9b534c 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JUnit5Runner.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JUnit5Runner.kt @@ -35,7 +35,8 @@ class JUnit5Runner @Inject constructor(kFiles: KFiles) : GenericTestRunner() { override fun affinity(project: Project, context: KobaltContext) : Int { val result = - if (project.testDependencies.any { it.id.contains("jupiter") }) IAffinity.DEFAULT_POSITIVE_AFFINITY + 100 + if (project.testDependencies.any { it.id.contains("junit5") || it.id.contains("jupiter") }) + IAffinity.DEFAULT_POSITIVE_AFFINITY + 100 else 0 return result diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt index 4688d46f..5e2a9354 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt @@ -9,7 +9,6 @@ import com.beust.kobalt.api.annotation.ExportedProjectProperty import com.beust.kobalt.api.annotation.IncrementalTask import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.maven.DependencyManager -import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.maven.Md5 import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.misc.KFiles @@ -27,7 +26,6 @@ import javax.inject.Singleton */ @Singleton open class JvmCompilerPlugin @Inject constructor( - open val localRepo: LocalRepo, open val files: KFiles, open val dependencyManager: DependencyManager, open val executors: KobaltExecutors, @@ -159,6 +157,10 @@ open class JvmCompilerPlugin @Inject constructor( if (compilerContributors.isEmpty()) { throw KobaltException("Couldn't find any compiler for project ${project.name}") } else { + + // Generate BuildConfig if applicable + context.variant.maybeGenerateBuildConfig(project, context) + val allCompilers = compilerContributors.flatMap { it.compilersFor(project, context)}.sorted() /** @@ -185,8 +187,8 @@ open class JvmCompilerPlugin @Inject constructor( var done = false // The directory where the classes get compiled val buildDirectory = - if (isTest) File(project.buildDirectory, KFiles.TEST_CLASSES_DIR) - else File(project.classesDir(context)) + if (isTest) File(KFiles.joinDir(project.buildDirectory, KFiles.TEST_CLASSES_DIR)) + else File(KFiles.joinDir(project.classesDir(context))) allCompilersSorted.doWhile({ ! done }) { compiler -> val compilerResults = compilerUtils.invokeCompiler(project, context, compiler, @@ -224,7 +226,7 @@ open class JvmCompilerPlugin @Inject constructor( } @Task(name = "doc", description = "Generate the documentation for the project", group = GROUP_DOCUMENTATION, - runBefore = arrayOf("assemble")) + runBefore = arrayOf("assemble"), runAfter = arrayOf("clean")) fun taskJavadoc(project: Project): TaskResult { val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors) if (docGenerator != null) { diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt index 3f29427a..123e8b76 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt @@ -16,6 +16,5 @@ class KotlinJarFiles @Inject constructor(val dependencyManager: DependencyManage } val stdlib: File get() = getKotlinCompilerJar("stdlib") - val runtime: File get() = getKotlinCompilerJar("runtime") val compiler: File get() = getKotlinCompilerJar("compiler-embeddable") } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt index 345919c9..f4ee96f8 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt @@ -14,11 +14,14 @@ import org.testng.remote.strprotocol.MessageHelper import org.testng.remote.strprotocol.MessageHub import org.testng.remote.strprotocol.TestResultMessage import org.w3c.dom.Attr +import org.w3c.dom.NodeList import org.xml.sax.InputSource import java.io.File import java.io.FileReader import java.io.IOException import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.xpath.XPathConstants +import javax.xml.xpath.XPathFactory class TestNgRunner : GenericTestRunner() { @@ -27,7 +30,10 @@ class TestNgRunner : GenericTestRunner() { override val annotationPackage = "org.testng" override val runnerName = "TestNG" - fun defaultOutput(project: Project) = KFiles.joinDir(project.buildDirectory, "test-output") + private fun defaultOutputWithoutProjectDir(project: Project) + = KFiles.joinDir(project.buildDirectory, "test-output") + private fun defaultOutput(project: Project) + = KFiles.joinDir(project.directory, project.buildDirectory, "test-output") override fun args(project: Project, context: KobaltContext, classpath: List, testConfig: TestConfig) = arrayListOf().apply { @@ -39,7 +45,9 @@ class TestNgRunner : GenericTestRunner() { if (testConfig.testArgs.none { it == "-d" }) { add("-d") - add(defaultOutput(project)) + // Don't include the project directory here since the generic runner will cd to that directory before + // running the tests + add(defaultOutputWithoutProjectDir(project)) } if (testConfig.testArgs.size == 0) { @@ -77,6 +85,15 @@ class TestNgRunner : GenericTestRunner() { var failed = 0 var skipped = 0 var passed = 0 + val xp = XPathFactory.newInstance().newXPath() + val testMethods = xp.compile("/testng-results/suite/test/class/test-method[@status='FAIL']") + .evaluate(doc, XPathConstants.NODESET) + as NodeList + val failedMethods = arrayListOf() + repeat(testMethods.length) { + val tm = testMethods.item(it) + failedMethods.add(tm.attributes.getNamedItem("signature").textContent) + } repeat(root.attributes.length) { val attribute = root.attributes.item(it) if (attribute is Attr) when (attribute.name) { @@ -90,6 +107,7 @@ class TestNgRunner : GenericTestRunner() { shortMessage = "$passed tests" } else if (failed > 0) { shortMessage = "$failed failed" + (if (skipped > 0) ", $skipped skipped" else "") + " tests" + longMessage = "Failed tests:\n " + failedMethods.joinToString("\n ") } } } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Gpg.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Gpg.kt index 27eeee83..60a4335c 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Gpg.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Gpg.kt @@ -1,16 +1,18 @@ package com.beust.kobalt.maven import com.beust.kobalt.OperatingSystem +import com.beust.kobalt.misc.LocalProperties import com.beust.kobalt.misc.error import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.warn +import com.google.inject.Inject import com.google.inject.Singleton import java.io.BufferedReader import java.io.File import java.io.InputStreamReader @Singleton -class Gpg { +class Gpg @Inject constructor(val localProperties: LocalProperties) { val COMMANDS = listOf("gpg", "gpg2") fun findGpgCommand() : String? { @@ -42,6 +44,21 @@ class Gpg { ascFile.delete() val allArgs = arrayListOf() allArgs.add(gpg) + + fun maybeAdd(prop: String, f: (String) -> Unit) = localProperties.getNoThrows(prop)?.let { + f(it) + } + + maybeAdd("gpg.password") { + allArgs.addAll(listOf("--passphrase", it, "--batch", "--yes")) + } + maybeAdd("gpg.keyId") { + allArgs.addAll(listOf("--local-user", it)) + } + maybeAdd("gpg.secretKeyRingFile") { + allArgs.addAll(listOf("--secret-keyring", "\"$it\"")) + } + allArgs.add("-ab") allArgs.add(file.absolutePath) diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/Booter.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/Booter.kt index e3b52dcd..02917929 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/Booter.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/Booter.kt @@ -2,6 +2,7 @@ package com.beust.kobalt.maven.aether import com.beust.kobalt.internal.KobaltSettings import com.google.common.eventbus.EventBus +import com.beust.kobalt.Args import org.eclipse.aether.DefaultRepositorySystemSession import org.eclipse.aether.RepositorySystem import org.eclipse.aether.repository.LocalRepository @@ -32,8 +33,9 @@ object Booter { // } fun newRepositorySystemSession(system: RepositorySystem, repo: File, settings: KobaltSettings, - eventBus: EventBus): DefaultRepositorySystemSession { + args: Args, eventBus: EventBus): DefaultRepositorySystemSession { val session = MavenRepositorySystemUtils.newSession(settings) + session.isOffline = args.offline val localRepo = LocalRepository(repo.absolutePath) session.localRepositoryManager = system.newLocalRepositoryManager(session, localRepo) diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/KobaltMavenResolver.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/KobaltMavenResolver.kt index 06a7c993..7c8b705f 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/KobaltMavenResolver.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/aether/KobaltMavenResolver.kt @@ -52,7 +52,7 @@ class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings, } fun error(s1: String, s2: String) { throw KobaltException("Found \"$s1\" but not \"$s2\" in local.properties for ${Kurl.KEY}.$host", - docUrl = "http://beust.com/kobalt/documentation/index.html#maven-repos-authenticated") + docUrl = "https://beust.com/kobalt/documentation/index.html#maven-repos-authenticated") } if (! hostInfo.username.isNullOrBlank() && hostInfo.password.isNullOrBlank()) { error("username", "password") @@ -141,7 +141,7 @@ class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings, fun create(id: String, optional: Boolean) = AetherDependency(DefaultArtifact(id), optional, args) private val system = Booter.newRepositorySystem() - private val session = Booter.newRepositorySystemSession(system, localRepo.localRepo, settings, eventBus) + private val session = Booter.newRepositorySystemSession(system, localRepo.localRepo, settings, args, eventBus) private fun createRepo(hostConfig: HostConfig) : RemoteRepository { val builder = RemoteRepository.Builder(hostConfig.name, "default", hostConfig.url) diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Git.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Git.kt index f8892390..cf6b5885 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Git.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Git.kt @@ -6,10 +6,11 @@ import com.google.inject.Inject import java.io.File class Git @Inject constructor() { - fun maybeTagRelease(project: Project, uploadResult: TaskResult, enabled: Boolean, annotated: Boolean, tag: String, message: String) : TaskResult { + fun maybeTagRelease(project: Project, uploadResult: TaskResult, enabled: Boolean, annotated: Boolean, + push: Boolean, tag: String, message: String) : TaskResult { val result = if (uploadResult.success && enabled) { - val tagSuccess = tagRelease(project, annotated, tag, message) + val tagSuccess = tagRelease(project, annotated, push, tag, message) if (! tagSuccess) { TaskResult(false, errorMessage = "Couldn't tag the project") } else { @@ -21,7 +22,7 @@ class Git @Inject constructor() { return result } - private fun tagRelease(project: Project, annotated: Boolean, tag: String, message: String) : Boolean { + private fun tagRelease(project: Project, annotated: Boolean, push: Boolean, tag: String, message: String) : Boolean { val version = if (tag.isNullOrBlank()) project.version else tag val success = try { log(2, "Tagging this release as \"$version\"") @@ -37,7 +38,9 @@ class Git @Inject constructor() { } else { git.tag().setName(version).setMessage(message).call() } - git.push().setPushTags().call() + if (push) { + git.push().setPushTags().call() + } true } catch(ex: Exception) { warn("Couldn't create tag ${version}: ${ex.message}", ex) diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/GithubApi2.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/GithubApi2.kt index 9f89a01d..b33286e0 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/GithubApi2.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/GithubApi2.kt @@ -86,12 +86,12 @@ class GithubApi2 @Inject constructor( .execute() val code = response.code() if (code != Http.CREATED) { - val error = Gson().fromJson(response.errorBody().string(), RetrofitError::class.java) + val error = Gson().fromJson(response.errorBody()?.string(), RetrofitError::class.java) throw KobaltException("Couldn't upload release, ${error.message}: " + error.errors[0].code) } else { val body = response.body() - uploadAsset(accessToken, body.uploadUrl!!, Http.TypedFile("application/zip", zipFile), tagName) + uploadAsset(accessToken, body?.uploadUrl!!, Http.TypedFile("application/zip", zipFile), tagName) .toBlocking() .forEach { action -> kobaltLog(1, "\n${zipFile.name} successfully uploaded") @@ -120,8 +120,8 @@ class GithubApi2 @Inject constructor( Duration.between(VersionCheckTimestampFile.timestamp, Instant.now())) { kobaltLog(2, "Skipping GitHub latest release check, too soon.") } else { - val username = localProperties.getNoThrows(PROPERTY_USERNAME, DOC_URL) - val accessToken = localProperties.getNoThrows(PROPERTY_ACCESS_TOKEN, DOC_URL) + val username = localProperties.getNoThrows(PROPERTY_USERNAME) + val accessToken = localProperties.getNoThrows(PROPERTY_ACCESS_TOKEN) try { val req = if (username != null && accessToken != null) { @@ -138,8 +138,8 @@ class GithubApi2 @Inject constructor( val releases = ex.body() if (releases != null) { releases.firstOrNull()?.let { - try { - result = listOf(it.name, it.tagName).filterNotNull().first { !it.isBlank() } + result = try { + listOf(it.name, it.tagName).filterNotNull().first { !it.isBlank() } } catch(ex: NoSuchElementException) { throw KobaltException("Couldn't find the latest release") } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt index d7199542..fcf5b86a 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt @@ -55,10 +55,13 @@ class KFiles { val previousVersion = latestInstalledVersion().version val previousJar = joinDir(distributionsDir, "kobalt-" + previousVersion, "kobalt/wrapper/kobalt-$previousVersion.jar") - val v = latestInstalledVersion() + latestInstalledVersion() val result = listOf("", "modules/kobalt-plugin-api", "modules/wrapper").map { - File(homeDir(KFiles.joinDir("kotlin", "kobalt", it, "kobaltBuild", "classes"))) - .absolutePath + File(homeDir(KFiles.joinDir("kotlin", "kobalt", it, "kobaltBuild", "classes"))) //kobalt build dirs + .absolutePath + } + listOf("modules/kobalt", "modules/kobalt-plugin-api", "modules/wrapper").map { + File(homeDir(KFiles.joinDir("kotlin", "kobalt", it, "target", "classes"))) //maven build dirs + .absolutePath } + listOf(previousJar) debug("Couldn't find ${jarFile.absolutePath}, using\n " + result.joinToString(" ")) return result.filter { File(it).exists() } @@ -134,7 +137,7 @@ class KFiles { fun joinFileAndMakeDir(vararg ts: String) = joinDir(joinAndMakeDir(ts.slice(0..ts.size - 2)), ts[ts.size - 1]) fun fixSlashes(f: File) = f.normalize().path.replace('\\', '/') - fun fixSlashes(s: String) = fixSlashes(File(s)) + fun fixSlashes(s: String) = s.replace('\\', '/') fun makeDir(dir: String, s: String? = null) = (if (s != null) File(dir, s) else File(dir)).apply { mkdirs() } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt index 67d31496..e2bd89de 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt @@ -51,7 +51,7 @@ fun Any.error(text: CharSequence, e: Throwable? = null) { object KobaltLogger { var LOG_LEVEL: Int = 1 - + val isQuiet: Boolean get() = (LOG_LEVEL == Constants.LOG_QUIET_LEVEL) val logger: Logger get() = @@ -60,6 +60,14 @@ object KobaltLogger { } else { Logger(false) } + + fun setLogLevel(args: Args) { + LOG_LEVEL = when { + args.log < Constants.LOG_QUIET_LEVEL -> Constants.LOG_DEFAULT_LEVEL + args.log > Constants.LOG_MAX_LEVEL -> Constants.LOG_MAX_LEVEL + else -> args.log + } + } } class Logger(val dev: Boolean) { diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltWrapperProperties.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltWrapperProperties.kt index 06d01e7b..a7b5177d 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltWrapperProperties.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KobaltWrapperProperties.kt @@ -24,7 +24,7 @@ class KobaltWrapperProperties @Inject constructor() { } private fun defaultUrlFor(version: String) = - "http://beust.com/kobalt/kobalt-$version.zip" + "https://beust.com/kobalt/kobalt-$version.zip" private val file: File get() = File("$WRAPPER_DIR/$KOBALT_WRAPPER_PROPERTIES") diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/LocalProperties.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/LocalProperties.kt index 4fe16a5c..2cf0775e 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/LocalProperties.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/LocalProperties.kt @@ -6,6 +6,9 @@ import java.nio.file.Files import java.nio.file.Paths import java.util.* +/** + * Encapsulate read access to local.properties. + */ @Singleton class LocalProperties { val localProperties: Properties by lazy { @@ -22,11 +25,11 @@ class LocalProperties { result } - fun getNoThrows(name: String, docUrl: String? = null) = localProperties.getProperty(name) + fun getNoThrows(name: String): String? = localProperties.getProperty(name) fun get(name: String, docUrl: String? = null) : String { - val result = getNoThrows(name, docUrl) + val result = getNoThrows(name) ?: throw KobaltException("Couldn't find $name in local.properties", docUrl = docUrl) - return result as String + return result } } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/NewRunCommand.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/NewRunCommand.kt index 7188cf10..e105133b 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/NewRunCommand.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/NewRunCommand.kt @@ -19,6 +19,7 @@ class RunCommandInfo { */ var useErrorStreamAsErrorIndicator : Boolean = true var useInputStreamAsErrorIndicator : Boolean = false + var ignoreExitValue : Boolean = false var errorCallback: Function1, Unit> = NewRunCommand.DEFAULT_ERROR var successCallback: Function1, Unit> = NewRunCommand.DEFAULT_SUCCESS @@ -78,7 +79,11 @@ open class NewRunCommand(val info: RunCommandInfo) { val process = pb.start() // Run the command and collect the return code and streams - val returnCode = process.waitFor(30, TimeUnit.SECONDS) + val processFinished = process.waitFor(120, TimeUnit.SECONDS) + + if (!processFinished) + kobaltError("process timed out!") + val input = if (process.inputStream.available() > 0) fromStream(process.inputStream) else listOf() @@ -86,13 +91,19 @@ open class NewRunCommand(val info: RunCommandInfo) { if (process.errorStream.available() > 0) fromStream(process.errorStream) else listOf() + kobaltLog(3, "info contains errors: " + (info.containsErrors != null)) + // Check to see if the command succeeded val isSuccess = if (info.containsErrors != null) ! info.containsErrors!!(error) - else isSuccess(returnCode, input, error) + else isSuccess(if (info.ignoreExitValue) true else processFinished, input, error) if (isSuccess) { - info.successCallback(input) + if (!info.useErrorStreamAsErrorIndicator) { + info.successCallback(error + input) + } else { + info.successCallback(input) + } } else { info.errorCallback(error + input) } @@ -105,7 +116,7 @@ open class NewRunCommand(val info: RunCommandInfo) { * have various ways to signal errors. */ open protected fun isSuccess(isSuccess: Boolean, input: List, error: List) : Boolean { - var hasErrors = ! isSuccess + var hasErrors: Boolean = ! isSuccess if (info.useErrorStreamAsErrorIndicator && ! hasErrors) { hasErrors = hasErrors || error.isNotEmpty() } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/StringVersion.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/StringVersion.kt index fc620554..b421e558 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/StringVersion.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/StringVersion.kt @@ -29,8 +29,12 @@ class StringVersion(val version: String) : Comparable { if (v1 < v2) return -1 else if (v1 > v2) return 1 } catch(ex: NumberFormatException) { - warn("Couldn't parse version $version or $other") - return -1 + if (version == other.toString()) { + return 0 + } else { + log(2, "Couldn't parse version $version or $other") + return -1 + } } } return 0 diff --git a/modules/kobalt/build.gradle b/modules/kobalt/build.gradle new file mode 100644 index 00000000..57e009c7 --- /dev/null +++ b/modules/kobalt/build.gradle @@ -0,0 +1,79 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.2.71' + id 'com.github.johnrengelman.shadow' version '5.0.0' +} + +dependencies { + implementation project(':wrapper') + implementation project(':kobalt-plugin-api') + implementation "biz.aQute.bnd:biz.aQute.bndlib:$bndlib" + implementation 'com.github.spullara.mustache.java:compiler:0.9.5' + implementation "com.google.code.findbugs:jsr305:$findbugs" + implementation "com.sparkjava:spark-core:$spark" + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp" + implementation 'com.sun.activation:javax.activation:1.2.0' + implementation "com.sun.xml.bind:jaxb-core:$jaxb" + implementation "com.sun.xml.bind:jaxb-impl:$jaxb" + implementation "javax.inject:javax.inject:$inject" + implementation "javax.xml.bind:jaxb-api:$jaxb" + implementation "org.apache.maven.resolver:maven-resolver-spi:$mavenResolver" + implementation "org.codehaus.groovy:groovy:$groovy" + implementation "com.beust:jcommander:$jcommander" + implementation "com.google.code.gson:gson:$gson" + implementation "com.google.inject:guice:$guice" + implementation "com.google.inject.extensions:guice-assistedinject:$guice" + implementation "com.squareup.retrofit2:converter-gson:$retrofit" + implementation "com.squareup.retrofit2:retrofit:$retrofit" + implementation "org.apache.maven:maven-model:$maven" + implementation "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin" + testImplementation 'org.assertj:assertj-core:3.8.0' + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin" + testImplementation "org.testng:testng:$testng" +} + +sourceSets { + main.kotlin.srcDirs += "${rootProject.projectDir}../../src/main/kotlin" + test.kotlin.srcDirs += "${rootProject.projectDir}../../src/test/kotlin" +} + +shadowJar { + classifier = null +} + +test { + useTestNG() +} + +publishing { + publications { + shadow(MavenPublication) { publication -> + project.shadow.component(publication) + artifact sourcesJar + artifact javadocJar + + pom { + name = project.name + description = 'A build system in Kotlin' + url = 'https://beust.com/kobalt' + licenses { + license { + name = 'Apache-2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0' + } + } + developers { + developer { + name = 'Cedric Beust' + email = 'cedric@beust.com' + } + } + scm { + connection = 'scm:https://github.com/cbeust/kobalt.git' + developerConnection = 'scm:git@github.com:cbeust/kobalt.git' + url = 'https://github.com/cbeust/kobalt' + } + } + } + } +} diff --git a/modules/kobalt/pom.xml b/modules/kobalt/pom.xml new file mode 100644 index 00000000..44dc799c --- /dev/null +++ b/modules/kobalt/pom.xml @@ -0,0 +1,231 @@ + + 4.0.0 + + com.beust + kobalt-pom + 1.1.0 + ../.. + + + kobalt + jar + 1.1.0 + + + + com.beust + kobalt-plugin-api + 1.1.0 + + + com.beust + wrapper + 1.1.0 + + + org.jetbrains.kotlin + kotlin-compiler-embeddable + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + com.github.spullara.mustache.java + compiler + 0.9.5 + compile + + + javax.inject + javax.inject + 1 + compile + + + com.google.inject + guice + 4.2.2 + + + com.google.inject.extensions + guice-assistedinject + 4.2.2 + + + com.beust + jcommander + 1.72 + + + org.apache.maven + maven-model + 3.5.2 + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + com.google.code.gson + gson + 2.8.2 + + + com.squareup.retrofit2 + retrofit + 2.3.0 + + + com.squareup.retrofit2 + converter-gson + 2.3.0 + + + biz.aQute.bnd + biz.aQute.bndlib + 3.5.0 + + + com.squareup.okhttp3 + logging-interceptor + ${okhttp3.version} + + + com.sparkjava + spark-core + 2.6.0 + + + org.codehaus.groovy + groovy + 2.4.12 + + + org.apache.maven.resolver + maven-resolver-spi + ${mavenresolver.version} + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + com.sun.xml.bind + jaxb-impl + 2.3.0 + + + com.sun.xml.bind + jaxb-core + 2.3.0 + + + com.sun.activation + javax.activation + 1.2.0 + + + + org.assertj + assertj-core + 3.8.0 + test + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + org.testng + testng + ${testng.version} + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + + ${project.basedir}../../src/main/kotlin + + + + + test-compile + test-compile + + + ${project.basedir}../../src/test/kotlin + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + compile + + + java-test-compile + test-compile + testCompile + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 + + + + com.beust.kobalt.MainKt + + + + + + package + + shade + + + + + + + \ No newline at end of file diff --git a/modules/wrapper/build.gradle b/modules/wrapper/build.gradle new file mode 100644 index 00000000..c0b5dafe --- /dev/null +++ b/modules/wrapper/build.gradle @@ -0,0 +1,38 @@ +jar { + manifest { + attributes 'Main-Class': 'com.beust.kobalt.wrapper.Main' + } +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact sourcesJar + artifact javadocJar + + pom { + name = project.name + description = 'Wrapper for Kobalt' + url = 'https://beust.com/kobalt' + licenses { + license { + name = 'Apache-2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0' + } + } + developers { + developer { + name = 'Cedric Beust' + email = 'cedric@beust.com' + } + } + scm { + connection = 'scm:https://github.com/cbeust/kobalt.git' + developerConnection = 'scm:git@github.com:cbeust/kobalt.git' + url = 'https://github.com/cbeust/kobalt' + } + } + } + } +} diff --git a/modules/wrapper/pom.xml b/modules/wrapper/pom.xml new file mode 100644 index 00000000..a9dc8796 --- /dev/null +++ b/modules/wrapper/pom.xml @@ -0,0 +1,28 @@ + + 4.0.0 + + com.beust + kobalt-pom + 1.1.0 + ../.. + + + wrapper + jar + 1.1.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.7 + 1.7 + + + + + \ No newline at end of file diff --git a/modules/wrapper/src/main/java/com/beust/kobalt/wrapper/Main.java b/modules/wrapper/src/main/java/com/beust/kobalt/wrapper/Main.java index f57db6d2..f31bbc3f 100644 --- a/modules/wrapper/src/main/java/com/beust/kobalt/wrapper/Main.java +++ b/modules/wrapper/src/main/java/com/beust/kobalt/wrapper/Main.java @@ -47,7 +47,6 @@ public class Main { private int installAndLaunchMain(String[] argv) throws IOException, InterruptedException { String version = getVersion(); - initWrapperFile(version); List kobaltArgv = new ArrayList<>(); boolean noLaunch = false; @@ -78,6 +77,7 @@ public class Main { } int result = 0; if (! exit) { + initWrapperFile(version); Path kobaltJarFile = installDistribution(); if (!noLaunch) { result = launchMain(kobaltJarFile, kobaltArgv); @@ -118,7 +118,7 @@ public class Main { } private static String downloadUrl(String version) { - return "http://beust.com/kobalt/kobalt-" + version + ".zip"; + return "https://beust.com/kobalt/kobalt-" + version + ".zip"; } private void initWrapperFile(String version) throws IOException { @@ -133,7 +133,7 @@ public class Main { } private String getWrapperVersion() { - return wrapperProperties.getProperty(PROPERTY_VERSION); + return wrapperProperties.getProperty(PROPERTY_VERSION, "N/A"); } private String getWrapperDownloadUrl(String version) { diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..3a87c7ac --- /dev/null +++ b/pom.xml @@ -0,0 +1,34 @@ + + 4.0.0 + + com.beust + kobalt-pom + pom + 1.1.0 + + + modules/kobalt-plugin-api + modules/wrapper + modules/kobalt + + + + + testng + https://dl.bintray.com/cbeust/maven + + + + + 1.2.71 + 1.13.0 + 3.9.1 + 1.1.0 + 1.1.0 + 5.1.0 + 6.12 + 1.7.3 + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..c36e45fd --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'kobalt-pom' +include(':kobalt-plugin-api', ':wrapper', ':kobalt') +project(':kobalt-plugin-api').projectDir = file('modules/kobalt-plugin-api') +project(':wrapper').projectDir = file('modules/wrapper') +project(':kobalt').projectDir = file('modules/kobalt') diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index aeedb001..19b85404 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -38,6 +38,14 @@ class Main @Inject constructor( companion object { fun mainNoExit(argv: Array): Int { val (jc, args) = parseArgs(argv) + if (args.usage) { + jc.usage() + return 0 + } + if (args.version) { + println("Kobalt ${Kobalt.version}") + return 0 + } Kobalt.init(MainModule(args, KobaltSettings.readSettingsXml())) val result = launchMain(Kobalt.INJECTOR.getInstance(Main::class.java), jc, args, argv) return result @@ -47,11 +55,7 @@ class Main @Inject constructor( val args = Args() val result = JCommander(args) result.parse(*argv) - KobaltLogger.LOG_LEVEL = if (args.log < Constants.LOG_QUIET_LEVEL) { - Constants.LOG_DEFAULT_LEVEL - } else if (args.log > Constants.LOG_MAX_LEVEL) { - Constants.LOG_MAX_LEVEL - } else args.log + KobaltLogger.setLogLevel(args) return Main.RunInfo(result, args) } diff --git a/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt b/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt index 441939a2..e17a7cd8 100644 --- a/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt +++ b/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt @@ -20,6 +20,8 @@ abstract class LanguageTemplateGenerator : ITemplate { abstract val defaultSourceDirectories : HashSet abstract val defaultTestDirectories : HashSet + abstract val mainDependencies : ArrayList + abstract val testDependencies : ArrayList abstract val directive : String abstract val fileMatch : (String) -> Boolean abstract val fileMap: List @@ -131,20 +133,19 @@ abstract class LanguageTemplateGenerator : ITemplate { put("directory", currentDir.absolutePath) put("sourceDirectories", defaultSourceDirectories) put("sourceDirectoriesTest", defaultTestDirectories) + put("mainDependencies", mainDependencies) + put("testDependencies", testDependencies) put("imports", "import com.beust.kobalt.plugin.$templateName.*") put("directive", "project") } - var mainDeps = arrayListOf() - var testDeps = arrayListOf() - map.put("mainDependencies", mainDeps) - map.put("testDependencies", testDeps) File("pom.xml").let { if (it.absoluteFile.exists()) { - importPom(it, mainDeps, testDeps, map) + importPom(it, mainDependencies, testDependencies, map) } } + val fileInputStream = javaClass.classLoader .getResource(ITemplateContributor.DIRECTORY_NAME + "/build.mustache").openStream() val sw = StringWriter() diff --git a/src/main/kotlin/com/beust/kobalt/app/Profiles.kt b/src/main/kotlin/com/beust/kobalt/app/Profiles.kt index bb5ea346..b2cf1a5a 100644 --- a/src/main/kotlin/com/beust/kobalt/app/Profiles.kt +++ b/src/main/kotlin/com/beust/kobalt/app/Profiles.kt @@ -56,7 +56,7 @@ class Profiles(val context: KobaltContext) { val variable = if (match.first) match.second else oldMatch.second if (oldMatch.first) { - warn("Old profile syntax detected for \"$line\"," + + warn("Old profile syntax detected for \"${line.trim()}\"," + " please update to \"val $variable by profile()\"") } diff --git a/src/main/kotlin/com/beust/kobalt/app/java/JavaTemplateGenerator.kt b/src/main/kotlin/com/beust/kobalt/app/java/JavaTemplateGenerator.kt index c34b80d3..ef938f00 100644 --- a/src/main/kotlin/com/beust/kobalt/app/java/JavaTemplateGenerator.kt +++ b/src/main/kotlin/com/beust/kobalt/app/java/JavaTemplateGenerator.kt @@ -1,11 +1,14 @@ package com.beust.kobalt.app.java import com.beust.kobalt.app.LanguageTemplateGenerator +import com.beust.kobalt.maven.Pom /** * Template for the "java" generator. */ class JavaTemplateGenerator : LanguageTemplateGenerator() { + override val mainDependencies = arrayListOf() + override val testDependencies = arrayListOf() override val defaultSourceDirectories = hashSetOf("src/main/java") override val defaultTestDirectories = hashSetOf("src/test/java") override val directive = "project" diff --git a/src/main/kotlin/com/beust/kobalt/app/kotlin/KotlinTemplateGenerator.kt b/src/main/kotlin/com/beust/kobalt/app/kotlin/KotlinTemplateGenerator.kt index 51b11a14..f10698c4 100644 --- a/src/main/kotlin/com/beust/kobalt/app/kotlin/KotlinTemplateGenerator.kt +++ b/src/main/kotlin/com/beust/kobalt/app/kotlin/KotlinTemplateGenerator.kt @@ -1,10 +1,16 @@ package com.beust.kobalt.app.kotlin +import com.beust.kobalt.Constants import com.beust.kobalt.app.LanguageTemplateGenerator +import com.beust.kobalt.maven.Pom class KotlinTemplateGenerator : LanguageTemplateGenerator() { override val defaultSourceDirectories = hashSetOf("src/main/kotlin") override val defaultTestDirectories = hashSetOf("src/test/kotlin") + override val mainDependencies = arrayListOf( + Pom.Dependency("org.jetbrains.kotlin", "kotlin-stdlib", null, Constants.KOTLIN_COMPILER_VERSION) + ) + override val testDependencies = arrayListOf() override val directive = "project" override val templateName = "kotlin" override val templateDescription = "Generate a simple Kotlin project" diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt index a7c0a312..41d9fdd4 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt @@ -12,15 +12,7 @@ import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.warn import com.google.gson.Gson import com.google.inject.Guice -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.ResponseBody -import okhttp3.ws.WebSocket -import okhttp3.ws.WebSocketCall -import okhttp3.ws.WebSocketListener -import okio.Buffer -import java.io.IOException +import okhttp3.* fun main(argv: Array) { Kobalt.INJECTOR = Guice.createInjector(MainModule(Args(), KobaltSettings.readSettingsXml())) @@ -39,26 +31,22 @@ class KobaltClient : Runnable { .url("$url?projectRoot=$projectRoot&buildFile=$buildFile") .build() var webSocket: WebSocket? = null - val ws = WebSocketCall.create(client, request).enqueue(object: WebSocketListener { - override fun onOpen(ws: WebSocket, response: Response) { - webSocket = ws - } - - override fun onPong(p0: Buffer?) { - println("WebSocket pong") - } - - override fun onClose(p0: Int, p1: String?) { - println("WebSocket closed") - } - - override fun onFailure(ex: IOException, response: Response?) { + val socketListener = object: WebSocketListener() { + override fun onFailure(webSocket: WebSocket, ex: Throwable, response: Response?) { Exceptions.printStackTrace(ex) error("WebSocket failure: ${ex.message} response: $response") } - override fun onMessage(body: ResponseBody) { - val json = body.string() + override fun onOpen(ws: WebSocket, response: Response) { + webSocket = ws + } + + override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { + println("Closing socket") + } + + override fun onMessage(webSocket: WebSocket, text: String) { + val json = text val wsCommand = Gson().fromJson(json, WebSocketCommand::class.java) if (wsCommand.errorMessage != null) { warn("Received error message from server: " + wsCommand.errorMessage) @@ -87,7 +75,10 @@ class KobaltClient : Runnable { } } } - }) + } + + val ws = client.newWebSocket(request, socketListener) + ws.close(1000, "All good") } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt index 2c7433d7..926a00bf 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt @@ -17,7 +17,6 @@ import com.beust.kobalt.plugin.packaging.PackageConfig import com.beust.kobalt.plugin.packaging.PackagingPlugin import com.google.inject.Inject import com.google.inject.Singleton -import org.jetbrains.kotlin.config.TargetPlatformVersion.NoVersion.description import java.io.File class ApplicationConfig { @@ -34,6 +33,15 @@ class ApplicationConfig { @Directive fun args(vararg argv: String) = argv.forEach { args.add(it) } val args = arrayListOf() + + @Directive + var ignoreErrorStream: Boolean = false + + @Directive + var ignoreInputStream: Boolean = true + + @Directive + var ignoreExitValue: Boolean = false } @Directive @@ -139,6 +147,7 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigsActor -> kobaltLog(1, output.joinToString("\n")) @@ -147,6 +156,9 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigsActor context.logger.log(project.name, 1, " Deleting " + path) @@ -64,9 +62,10 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va // IClasspathContributor override fun classpathEntriesFor(project: Project?, context: KobaltContext): Collection { val result = arrayListOf() + val kaptConfig = kaptConfigs[project?.name] if (project != null && kaptConfig != null) { - kaptConfig?.let { config -> - val c = generatedClasses(project, context, config.outputDir) + kaptConfig.let { config -> + val c = kaptClassesDir(project, config.outputDir) File(c).mkdirs() result.add(FileDependency(c)) } @@ -74,45 +73,46 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va return result } - private fun generatedDir(project: Project, outputDir: String) : File + private fun aptGeneratedDir(project: Project, outputDir: String) : File = File(KFiles.joinDir(project.directory, KFiles.KOBALT_BUILD_DIR, outputDir)) // ISourceDirectoryContributor override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List { val result = arrayListOf() aptConfigs[project.name]?.let { config -> - result.add(generatedDir(project, config.outputDir)) + result.add(aptGeneratedDir(project, config.outputDir)) } kaptConfigs[project.name]?.let { config -> - result.add(generatedDir(project, config.outputDir)) + result.add(File(kaptSourcesDir(project, config.outputDir))) } return result } - private fun generated(project: Project, context: KobaltContext, outputDir: String) = + private fun kaptGenerated(project: Project, outputDir: String) = KFiles.joinAndMakeDir(project.directory, project.buildDirectory, outputDir) - private fun generatedSources(project: Project, context: KobaltContext, outputDir: String) = - KFiles.joinDir(generated(project, context, outputDir), "sources") - private fun generatedStubs(project: Project, context: KobaltContext, outputDir: String) = - KFiles.joinDir(generated(project, context, outputDir), "stubs") - private fun generatedClasses(project: Project, context: KobaltContext, outputDir: String) = - KFiles.joinDir(generated(project, context, outputDir), "classes") + private fun kaptSourcesDir(project: Project, outputDir: String) = + KFiles.joinDir(kaptGenerated(project, outputDir), "sources") + private fun kaptStubsDir(project: Project, outputDir: String) = + KFiles.joinDir(kaptGenerated(project, outputDir), "stubs") + private fun kaptClassesDir(project: Project, outputDir: String) = + KFiles.joinDir(kaptGenerated(project, outputDir), "classes") // ITaskContributor override fun tasksFor(project: Project, context: KobaltContext): List { + val kaptConfig = kaptConfigs[project.name] val result = if (kaptConfig != null) { listOf( DynamicTask(this, "runKapt", "Run kapt", AnnotationDefault.GROUP, project, reverseDependsOn = listOf("compile"), runAfter = listOf("clean"), - closure = {p: Project -> taskRunKapt(p)}), + closure = {p: Project -> taskRunKapt(p)}), DynamicTask(this, "compileKapt", "Compile the sources generated by kapt", AnnotationDefault.GROUP, project, dependsOn = listOf("runKapt"), reverseDependsOn = listOf("compile"), - closure = {p: Project -> taskCompileKapt(p)}) + closure = {p: Project -> taskCompileKapt(p)}) ) } else { emptyList() @@ -124,11 +124,11 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va var success = true kaptConfigs[project.name]?.let { config -> val sourceDirs = listOf( - generatedStubs(project, context, config.outputDir), - generatedSources(project, context, config.outputDir)) + kaptStubsDir(project, config.outputDir), + kaptSourcesDir(project, config.outputDir)) val sourceFiles = KFiles.findSourceFiles(project.directory, sourceDirs, listOf("kt")).toList() val buildDirectory = File(KFiles.joinDir(project.directory, - generatedClasses(project, context, config.outputDir))) + kaptClassesDir(project, config.outputDir))) val flags = listOf() val cai = CompilerActionInfo(project.directory, allDependencies(project), sourceFiles, listOf(".kt"), buildDirectory, flags, emptyList(), forceRecompile = true, compilerSeparateProcess = true) @@ -158,9 +158,10 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va fun taskRunKapt(project: Project) : TaskResult { var success = true val flags = arrayListOf() + val kaptConfig = kaptConfigs[project.name] kaptConfig?.let { config -> - val generated = generated(project, context, config.outputDir) - val generatedSources = generatedSources(project, context, config.outputDir).replace("//", "/") + val generated = kaptGenerated(project, config.outputDir) + val generatedSources = kaptSourcesDir(project, config.outputDir).replace("//", "/") File(generatedSources).mkdirs() // @@ -191,8 +192,8 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va val kaptPluginFlags = arrayListOf() val verbose = KobaltLogger.LOG_LEVEL >= 2 listOf("sources=" + generatedSources, - "classes=" + generatedClasses(project, context, config.outputDir), - "stubs=" + generatedStubs(project, context, config.outputDir), + "classes=" + kaptClassesDir(project, config.outputDir), + "stubs=" + kaptStubsDir(project, config.outputDir), "verbose=$verbose", "aptOnly=true").forEach { kaptPluginFlags.add(kaptPluginFlag(it)) @@ -223,6 +224,7 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va val cai = CompilerActionInfo(project.directory, allDeps, sourceFiles, listOf(".kt"), buildDirectory, flags, emptyList(), forceRecompile = true, compilerSeparateProcess = true) + context.logger.log(project.name, 2, "kapt3 flags:") context.logger.log(project.name, 2, " " + kaptPluginFlags.joinToString("\n ")) val cr = compilerUtils.invokeCompiler(project, context, kotlinPlugin.compiler, cai) success = cr.failedResult == null @@ -242,9 +244,9 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va fun addFlags(outputDir: String) { aptDependencies[project.name]?.let { result.add("-s") - generatedSources(project, context, outputDir).let { generatedSource -> - File(generatedSource).mkdirs() - result.add(generatedSource) + aptGeneratedDir(project, outputDir).let { generatedSource -> + generatedSource.mkdirs() + result.add(generatedSource.path) } } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt index 9f6108d2..0b4d2e4b 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt @@ -44,9 +44,18 @@ class JavaPlugin @Inject constructor(val javaCompiler: JavaCompiler, override va // IDocFlagContributor override fun docFlagsFor(project: Project, context: KobaltContext, currentFlags: List, suffixesBeingCompiled: List): List { - return listOf("-d", "javadoc", "-Xdoclint:none", "-Xmaxerrs", "1", "-quiet") + val config = javadocConfigurations[project.name] + return if (config == null || config.args.isEmpty()) DEFAULT_JAVADOC_ARGS + else config.args } + val DEFAULT_JAVADOC_ARGS = listOf("-d", "javadoc", "-Xdoclint:none", "-Xmaxerrs", "1", "-quiet") + + val javadocConfigurations = hashMapOf() + + fun addJavadocConfiguration(project: Project, configuration: JavadocConfig) + = javadocConfigurations.put(project.name, configuration) + // ICompilerContributor val compiler = CompilerDescription(PLUGIN_NAME, "java", SOURCE_SUFFIXES, javaCompiler) @@ -77,4 +86,12 @@ fun Project.javaCompiler(init: JavaConfig.() -> Unit) = JavaConfig(this).also { config -> config.init() (Kobalt.findPlugin(JavaPlugin.PLUGIN_NAME) as JavaPlugin).addConfiguration(this, config) - } \ No newline at end of file + } + +@Directive +fun Project.javadoc(init: JavadocConfig.() -> Unit) = + JavadocConfig(this).also { config -> + config.init() + (Kobalt.findPlugin(JavaPlugin.PLUGIN_NAME) as JavaPlugin).addJavadocConfiguration(this, config) + } + diff --git a/src/main/kotlin/com/beust/kobalt/plugin/java/JavadocConfig.kt b/src/main/kotlin/com/beust/kobalt/plugin/java/JavadocConfig.kt new file mode 100644 index 00000000..7129dcaa --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/plugin/java/JavadocConfig.kt @@ -0,0 +1,603 @@ +package com.beust.kobalt.plugin.java + +import com.beust.kobalt.api.Project +import com.google.inject.Singleton +import java.io.BufferedReader +import java.io.File +import java.io.InputStream +import java.io.InputStreamReader +import java.util.concurrent.TimeUnit + +@Singleton +class JavadocConfig(val project: Project) { + val args = arrayListOf("-Xdoclint:none", "-Xmaxerrs", "1", "-quiet") + + private fun removeArg(match: String, startsWith: Boolean = false, pair: Boolean = false) { + val it = args.iterator() + while (it.hasNext()) { + val next = it.next() + var removed = false + if (startsWith) { + if (next.startsWith(match)) { + it.remove() + removed = true + } + } else if (next == match) { + it.remove() + removed = true + } + // If it's a pair, delete the next arg too. + if (pair && removed && it.hasNext()) { + it.next() + it.remove() + } + } + } + + private fun addInt(option: String, value: Int): Int { + args.add("-$option") + args.add(value.toString()) + return value + } + + private fun addBoolean(option: String, value: Boolean): Boolean { + args.remove("-$option") + if (value) { + args.add("-$option") + } + return value + } + + private fun addString(option: String, value: String): String { + if (value.isNotEmpty()) { + args.add("-$option") + args.add("\"$value\"") + } + return value + } + + private fun addStrings(option: String, vararg value: String) { + value.forEach { + addString(option, it) + } + } + + private fun addPair(option: String, first: String, second: String) { + if (first.isNotEmpty() && second.isNotEmpty()) { + args.add("-$option") + args.add("\"$first\"") + args.add("\"$second\"") + } + } + + private fun addFile(option: String, value: String): String { + val f = File(value) + if (f.exists()) { + args.add("-$option") + args.add("\"${f.absolutePath}\"") + } + return value + } + + /** + * Set arguments manually. + */ + fun args(vararg options: String) = args.addAll(options) + + // + // Jvm Options + // + + /** + * @see -Xdoclint + */ + var docLint: String = "none" + set(value) { + removeArg("-Xdoclint:", startsWith = true) + addString("Xdoclint:", value) + } + + /** + * @see -Xmaxerrs + */ + var maxErrs: Int = 1 + set(value) { + removeArg("-Xmaxerrs", startsWith = true, pair = true) + addInt("Xmaxerrs", value) + } + + /** + * @see -Xmaxwarns + */ + var maxWarns: Int = 1 + set(value) { + removeArg("-Xmaxwarns", startsWith = true, pair = true) + addInt("Xmaxwarns", value) + } + + // + // Javadoc Options + // + + /** + * @see -overview + */ + var overview: String = "" + set(value) { + addFile("overview", value) + } + + /** + * @see -public + */ + var public: Boolean = false + set(value) { + addBoolean("public", value) + } + + /** + * @see -protected + */ + var protected: Boolean = false + set(value) { + addBoolean("protected", value) + } + + /** + * @see -pakage + */ + var pkg: Boolean = false + set(value) { + addBoolean("package", pkg) + } + + /** + * @see -private + */ + var private: Boolean = false + set(value) { + addBoolean("private", private) + } + + /** + * @see -doclet + */ + var doclet: String = "" + set(value) { + addString("doclet", value) + } + + /** + * @see -docletpath + */ + var docletPath: String = "" + set(value) { + addString("docletpath", value) + } + + /** + * @see -source + */ + var source: String = "" + set(value) { + addString("source", source) + } + + /** + * @see -sourcepath + */ + var sourcePath: String = "" + set(value) { + addString("sourcepath", value) + } + + /** + * @see -classpath + */ + var classPath: String = "" + set(value) { + addString("classpath", value) + } + + /** + * @see -subpackages + */ + var subPackages: String = "" + set(value) { + addString("subpackages", value) + } + + /** + * @see -exclude + */ + var exclude: String = "" + set(value) { + addString("exclude", value) + } + + /** + * @see -bootClassPath + */ + var bootClassPath: String = "" + set(value) { + addString("bootclasspath", value) + } + + /** + * @see -extdirs + */ + var extDirs: String = "" + set(value) { + addString("extdirs", value) + } + + /** + * @see -verbose + */ + var verbose: Boolean = false + set(value) { + addBoolean("verbose", value) + } + + /** + * @see -quiet + */ + var quiet: Boolean = true + set(value) { + addBoolean("quiet", value) + } + + /** + * @see -breakiterator + */ + var breakIterator: Boolean = false + set(value) { + addBoolean("breakiterator", value) + } + + /** + * @see -locale + */ + var locale: String = "" + set(value) { + addString("locale", value) + } + + /** + * @see -encoding + */ + var encoding: String = "" + set(value) { + addString("encoding", value) + } + + /** + * @see -Jflag + */ + var jFlag: String = "" + set(value) { + addString("J-", value) + } + + // + // Standard Doclet + // + + /** + * @see -use + */ + var use: Boolean = false + set(value) { + addBoolean("use", value) + } + + /** + * @see -version + */ + var version: Boolean = false + set(value) { + addBoolean("version", value) + } + + /** + * @see -author + */ + var author: Boolean = false + set(value) { + addBoolean("author", value) + } + + /** + * @see -splitindex + */ + var splitIndex: Boolean = false + set(value) { + addBoolean("splitindex", value) + } + + /** + * Set both the [windowTitle] and [docTitle] + */ + var title: String = "" + set(value) { + windowTitle = value + docTitle = value + } + + /** + * @see -windowtitle + */ + var windowTitle: String = "" + set(value) { + addString("windowtitle", value) + } + + /** + * @see -doctitle + */ + var docTitle: String = "" + set(value) { + addString("doctitle", value) + } + + /** + * @see -header + */ + var header: String = "" + set(value) { + addString("header", value) + } + + /** + * @see -footer + */ + var footer: String = "" + set(value) { + addString("footer", value) + } + + /** + * @see -top + */ + var top: String = "" + set(value) { + addString("top", value) + } + + /** + * @see -bottom + */ + var bottom: String = "" + set(value) { + addString("bottom", value) + } + + /** + * @see -linksource + */ + var linkSource: Boolean = false + set(value) { + addBoolean("linksource", value) + } + + /** + * @see -nodeprecated + */ + var noDeprecated: Boolean = false + set(value) { + addBoolean("nodeprecated", value) + } + + /** + * @see -nodeprecatedlist + */ + var noDeprecatedList: Boolean = false + set(value) { + addBoolean("nodeprecatedlist", value) + } + + /** + * @see -nosince + */ + var noSince: Boolean = false + set(value) { + addBoolean("nosince", value) + } + + /** + * @see -notree + */ + var noTree: Boolean = false + set(value) { + addBoolean("notree", value) + } + + /** + * @see -noindex + */ + var noIndex: Boolean = false + set(value) { + addBoolean("noindex", value) + } + + /** + * @see -nohelp + */ + var noHelp: Boolean = false + set(value) { + addBoolean("nohelp", value) + } + + /** + * @see -nonavbar + */ + var noNavBar: Boolean = false + set(value) { + addBoolean("nonavbar", value) + } + + /** + * @see -helpfile + */ + var helpFile: String = "" + set(value) { + addFile("helpfile", value) + } + + /** + * @see -stylesheet + */ + var stylesheet: String = "" + set(value) { + addFile("stylesheet", value) + } + + /** + * @see -serialwarn + */ + var serialWarn: Boolean = false + set(value) { + addBoolean("serialwarn", value) + } + + /** + * @see -charset + */ + var charSet: String = "" + set(value) { + addString("charset", value) + } + + /** + * @see -docencoding + */ + var docEncoding: String = "" + set(value) { + addString("docencoding", value) + } + + /** + * @see -keywords + */ + var keywords: Boolean = false + set(value) { + addBoolean("keywords", value) + } + + /** + * @see -tagletpath + */ + var tagletPath: String = "" + set(value) { + addString("tagletpath", value) + } + + /** + * @see -docfilessubdirs + */ + var docFilesSubDirs: Boolean = false + set(value) { + addBoolean("docfilessubdirs", value) + } + + /** + * @see -excludedocfilessubdir + */ + var excludeDocFilesSubDir: String = "" + set(value) { + addString("excludedocfilessubdir", value) + } + + /** + * @see -noqualifiers + */ + var noQualifiers: String = "" + set(value) { + addString("noqualifier", value) + } + + /** + * @see -notimestamp + */ + var noTimestamp: Boolean = false + set(value) { + addBoolean("notimestamp", value) + } + + /** + * @see -nocomment + */ + var noComment: Boolean = false + set(value) { + addBoolean("nocomment", value) + } + + /** + * @see -sourcetab + */ + var sourceTab: String = "" + set(value) { + addString("sourcetab", value) + } + + /** + * @see -group + */ + fun group(groupHeading: String, packagePattern: String) = addPair("group", groupHeading, packagePattern) + + /** + * @see -linkoffline + */ + fun linkOffline(extdocURL: String, packagelistLoc: String) = addPair("linkoffline", extdocURL, packagelistLoc) + + /** + * @see -link + */ + fun links(vararg links: String) = addStrings("link", *links) + + /** + * @see -tag + */ + fun tags(vararg tags: String) = addStrings("tag", *tags) + + /** + * @see -taglets + */ + fun taglets(vararg taglets: String) = addStrings("taglet", *taglets) +} + +fun main(args: Array) { + fun fromStream(ins: InputStream): List { + val result = arrayListOf() + val br = BufferedReader(InputStreamReader(ins)) + var line = br.readLine() + + while (line != null) { + result.add(line) + println(line) + line = br.readLine() + } + + return result + } + + val config = JavadocConfig(Project()) + config.title = "This is a test." + config.verbose = true + config.quiet = false + config.links("http://docs.oracle.com/javase/8/docs/api/") + config.args.add(0, ".\\kobaltBuild\\docs\\javadoc") + config.args.add(0, "-d") + config.args.add(0, "javadoc") + config.args.add(".\\modules\\wrapper\\src\\main\\java\\com\\beust\\kobalt\\wrapper\\Config.java") + config.args.add(".\\modules\\wrapper\\src\\main\\java\\com\\beust\\kobalt\\wrapper\\Main.java") + + println(config.args.joinToString(" ")) + + val pb = ProcessBuilder().command(config.args.toList()) + pb.directory(File(".")) + val proc = pb.start() + val err = proc.waitFor(30, TimeUnit.SECONDS) + val stdout = if (proc.inputStream.available() > 0) fromStream(proc.inputStream) else emptyList() + val stderr = if (proc.errorStream.available() > 0) fromStream(proc.errorStream) else emptyList() +} \ No newline at end of file diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt index 93ad5601..c1429910 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt @@ -8,10 +8,12 @@ import com.beust.kobalt.maven.dependency.FileDependency import com.beust.kobalt.misc.* import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.incremental.ICReporter import org.jetbrains.kotlin.incremental.makeIncrementally @@ -72,29 +74,18 @@ class KotlinCompiler @Inject constructor( File(outputDir).parentFile.mkdirs() } val classpath = cp.joinToString(File.pathSeparator) - val allArgs = arrayListOf( - "-d", outputDir, - "-classpath", classpath, - *(info.compilerArgs.toTypedArray()), - *(info.sourceFiles.toTypedArray()) - ) - - // Get rid of annoying and useless warning - if (! info.compilerArgs.contains("-no-stdlib")) { - allArgs.add("-no-stdlib") - } // If the Kotlin compiler version in settings.xml is different from the default, we // need to spawn a Kotlin compiler in a separate process. Otherwise, we can just invoke // the K2JVMCompiler class directly val actualVersion = kotlinVersion(project) - if (settings.kobaltCompilerSeparateProcess || actualVersion != Constants.KOTLIN_COMPILER_VERSION + return if (settings.kobaltCompilerSeparateProcess || actualVersion != Constants.KOTLIN_COMPILER_VERSION || info.compilerSeparateProcess) { - return invokeCompilerInSeparateProcess(classpath, info, actualVersion, project) + invokeCompilerInSeparateProcess(classpath, info, actualVersion, project) } else { - return invokeCompilerDirectly(project, projectName ?: "kobalt-" + Random().nextInt(), outputDir, + invokeCompilerDirectly(project, projectName ?: "kobalt-" + Random().nextInt(), outputDir, info, classpath, filesToCompile) } } @@ -111,13 +102,22 @@ class KotlinCompiler @Inject constructor( .filterNotNull() .joinToString(" ") - val xFlagsArray = xFlagsString.split(" ").toTypedArray() ?: emptyArray() + val infoDir = info.directory + + val outputDir = + if (infoDir != null) { + KFiles.joinDir(infoDir, info.outputDir.path) + } else { + info.outputDir.path + } + + val xFlagsArray = xFlagsString.split(" ").toTypedArray() val newArgs = listOf( "-classpath", compilerClasspath, K2JVMCompiler::class.java.name, *info.compilerArgs.toTypedArray(), "-classpath", classpath, - "-d", info.outputDir.absolutePath, + "-d", outputDir, *xFlagsArray, *info.sourceFiles.toTypedArray()) .filter { ! it.isEmpty() } @@ -145,17 +145,17 @@ class KotlinCompiler @Inject constructor( // Collect the compiler args from kotlinCompiler{} and from settings.xml and parse them val args2 = info.compilerArgs + - (settings.kobaltCompilerFlags?.split(" ") ?: listOf()) + (settings.kobaltCompilerFlags?.split(" ") ?: listOf()) val args = K2JVMCompilerArguments() val compiler = K2JVMCompiler() - compiler.parseArguments(args2.toTypedArray(), args) + parseCommandLineArguments(args2, args) // Override important arguments with our values args.apply { moduleName = projectName destination = outputDir classpath = classpathString - freeArgs = sourceFiles + freeArgs = sourceFiles.toMutableList() friendPaths = friends } @@ -179,12 +179,12 @@ class KotlinCompiler @Inject constructor( "single-module" -> args.singleModule = true "load-builtins-from-dependencies" -> args.loadBuiltInsFromDependencies = true - "coroutines=enable" -> args.coroutinesEnable = true - "coroutines=warn" -> args.coroutinesWarn = true - "coroutines=error" -> args.coroutinesError = true + "coroutines=enable" -> args.coroutinesState = LanguageFeature.State.ENABLED.name + "coroutines=warn" -> args.coroutinesState = LanguageFeature.State.ENABLED_WITH_WARNING.name + "coroutines=error" -> args.coroutinesState = LanguageFeature.State.ENABLED_WITH_ERROR.name "no-inline" -> args.noInline = true "multi-platform" -> args.multiPlatform = true - "no-check-impl" -> args.noCheckImpl = true +// "no-check-impl" -> args.noCheckImpl = true else -> warn("Unknown Kotlin compiler flag found in config.xml: $it") } } @@ -214,7 +214,7 @@ class KotlinCompiler @Inject constructor( + " " + sourceFiles.joinToString(" ")) logk(2, " Additional kotlinc arguments: " + " -moduleName " + args.moduleName - + " -friendPaths " + args.friendPaths.joinToString(";")) + + " -friendPaths " + args.friendPaths?.joinToString(";")) val collector = object : MessageCollector { override fun clear() { throw UnsupportedOperationException("not implemented") @@ -225,7 +225,7 @@ class KotlinCompiler @Inject constructor( } fun dump(location: CompilerMessageLocation?, s: String) = - if (location != null && location.lineContent != null) { + if (location?.lineContent != null) { with(location) { "$lineContent\n$path:$line:$column $s" } @@ -233,11 +233,13 @@ class KotlinCompiler @Inject constructor( s } - override fun report(severity: CompilerMessageSeverity, - message: String, location: CompilerMessageLocation) { + override fun report(severity: CompilerMessageSeverity, message: String, + location: CompilerMessageLocation?) { if (severity.isError) { "Couldn't compile file: ${dump(location, message)}".let { fullMessage -> - throw KobaltException(fullMessage) + error(fullMessage) + val ex = KobaltException(fullMessage) + throw ex } } else if (severity == CompilerMessageSeverity.WARNING && KobaltLogger.LOG_LEVEL >= 2) { warn(dump(location, message)) @@ -251,24 +253,22 @@ class KotlinCompiler @Inject constructor( // // TODO: experimental should be removed as soon as it becomes standard // System.setProperty("kotlin.incremental.compilation.experimental", "true") - val result = - if (cliArgs.noIncrementalKotlin || Kobalt.context?.internalContext?.noIncrementalKotlin ?: false) { - log(2, " Kotlin incremental compilation is disabled") - val duration = benchmarkMillis { - compiler.exec(collector, Services.Builder().build(), args) - } - log(1, " Regular compilation time: ${duration.first} ms") - TaskResult(duration.second == ExitCode.OK) - } else { - log(1, " Kotlin incremental compilation is enabled") - val start = System.currentTimeMillis() - val duration = benchmarkMillis { - compileIncrementally(filesToCompile, sourceFiles, outputDir, info, args, collector) - } - log(1, " Incremental compilation time: ${duration.first} ms") - TaskResult() - } - return result + return if (cliArgs.noIncrementalKotlin || Kobalt.context?.internalContext?.noIncrementalKotlin ?: false) { + log(2, " Kotlin incremental compilation is disabled") + val duration = benchmarkMillis { + compiler.exec(collector, Services.Builder().build(), args) + } + log(1, " Regular compilation time: ${duration.first} ms") + TaskResult(duration.second == ExitCode.OK) + } else { + log(1, " Kotlin incremental compilation is enabled") + //val start = System.currentTimeMillis() + val duration = benchmarkMillis { + compileIncrementally(filesToCompile, sourceFiles, outputDir, info, args, collector) + } + log(1, " Incremental compilation time: ${duration.first} ms") + TaskResult() + } } private fun compileIncrementally(filesToCompile: Int, sourceFiles: List, outputDir: String?, @@ -382,8 +382,7 @@ class KotlinCompiler @Inject constructor( = dependencyManager.create("org.jetbrains" + ".kotlin:kotlin-compiler-embeddable:$version") fun compilerEmbeddableDependencies(project: Project?, version: String): List { - val deps = dependencyManager.transitiveClosure(listOf(compilerDep(version)), requiredBy = project?.name ?: "") - return deps + return dependencyManager.transitiveClosure(listOf(compilerDep(version)), requiredBy = project?.name ?: "") } /** @@ -416,7 +415,7 @@ class KotlinCompiler @Inject constructor( if (project != null) { listOf(KFiles.joinDir(project.directory, project.buildDirectory, KFiles.CLASSES_DIR)) } else { - emptyList() + emptyList() } val info = CompilerActionInfo(project?.directory, dependencies, sourceFiles, listOf("kt"), outputDir, args, friendPaths, context?.internalContext?.forceRecompile ?: false, compilerSeparateProcess) diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt index 3c437628..886f3537 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt @@ -99,9 +99,10 @@ class KotlinPlugin @Inject constructor(val executors: KobaltExecutors, val depen // IClasspathContributor override fun classpathEntriesFor(project: Project?, context: KobaltContext): List = - if (project == null || accept(project)) { + if (project == null || + context.pluginInfo.plugins.any { it is KotlinPlugin && it.settings.kobaltCompilerVersion == null }) { // All Kotlin projects automatically get the Kotlin runtime added to their class path - listOf(kotlinJarFiles.stdlib, kotlinJarFiles.runtime) + listOf(kotlinJarFiles.stdlib) .map { FileDependency(it.absolutePath) } } else { emptyList() diff --git a/src/main/kotlin/com/beust/kobalt/plugin/osgi/OsgiPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/osgi/OsgiPlugin.kt index d7fc7c0f..83ae5228 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/osgi/OsgiPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/osgi/OsgiPlugin.kt @@ -12,12 +12,12 @@ import com.beust.kobalt.plugin.packaging.PackagingPlugin import com.google.common.reflect.ClassPath import com.google.inject.Inject import com.google.inject.Singleton +import java.io.ByteArrayOutputStream import java.io.File -import java.net.URI import java.net.URLClassLoader -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.StandardOpenOption +import java.nio.file.* +import java.time.LocalDate +import java.time.format.DateTimeFormatter import java.util.jar.JarFile /** @@ -54,12 +54,14 @@ class OsgiPlugin @Inject constructor(val configActor: ConfigActor, v it + ";version=\"" + project.version + "\"" }.joinToString(",") + val toFile = Files.createTempFile(null, ".jar") val analyzer = Analyzer().apply { jar = aQute.bnd.osgi.Jar(jarName) val dependencies = project.compileDependencies + project.compileRuntimeDependencies dependencyManager.calculateDependencies(project, context, passedDependencies = dependencies).forEach { addClasspath(it.jarFile.get()) } + setProperty("Build-Date", LocalDate.now().format(DateTimeFormatter.ofPattern("y-MM-dd"))) setProperty(Analyzer.BUNDLE_VERSION, project.version) setProperty(Analyzer.BUNDLE_NAME, project.group + "." + project.artifactId) setProperty(Analyzer.BUNDLE_DESCRIPTION, project.description) @@ -72,31 +74,34 @@ class OsgiPlugin @Inject constructor(val configActor: ConfigActor, v } } - val manifest = analyzer.calcManifest() - val lines = manifest.mainAttributes.map { - it.key.toString() + ": " + it.value.toString() - } - - context.logger.log(project.name, 2, " Generated manifest:") - lines.forEach { - context.logger.log(project.name, 2, " $it") - } - - // - // Update or create META-INF/MANIFEST.MF - // - val uri = URI.create("jar:file:" + jarFile.absolutePath) - val options = hashMapOf() - val fileSystem = FileSystems.newFileSystem(uri, options) - fileSystem.use { fs -> - val mf = JarFile(jarFile).getEntry(MetaArchive.MANIFEST_MF) - if (mf == null) { - Files.createDirectories(fs.getPath("META-INF/")) + analyzer.calcManifest().let { manifest -> + val lines2 = ByteArrayOutputStream().use { baos -> + manifest.write(baos) + String(baos.toByteArray()) } - val jarManifest = fs.getPath(MetaArchive.MANIFEST_MF) - Files.write(jarManifest, lines, if (mf != null) StandardOpenOption.APPEND else StandardOpenOption.CREATE) + + context.logger.log(project.name, 2, " Generated manifest:\n$lines2") + + // + // Update or create META-INF/MANIFEST.MF + // + KFiles.copy(Paths.get(jarFile.toURI()), Paths.get(toFile.toUri())) + + val fileSystem = FileSystems.newFileSystem(toFile, null) + fileSystem.use { fs -> + JarFile(jarFile).use { jf -> + val mf = jf.getEntry(MetaArchive.MANIFEST_MF) + if (mf == null) { + Files.createDirectories(fs.getPath("META-INF/")) + } + val jarManifest = fs.getPath(MetaArchive.MANIFEST_MF) + Files.write(jarManifest, listOf(lines2), + if (mf != null) StandardOpenOption.APPEND else StandardOpenOption.CREATE) + } + } + Files.copy(Paths.get(toFile.toUri()), Paths.get(jarFile.toURI()), StandardCopyOption.REPLACE_EXISTING) + return TaskResult() } - return TaskResult() } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt index bf090514..b7871c90 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt @@ -105,7 +105,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana val outputFile = jarGenerator.fullArchiveName(project, context, it.name) outputFiles.add(outputFile) allIncludedFiles.addAll(files) - zipToFiles[it.name] = files + zipToFiles[outputFile.name] = files } } } @@ -148,9 +148,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana Pair(packageConfig.zips, zipGenerator) ) - pairs.forEach { pair -> - val zips = pair.first - val generator = pair.second + pairs.forEach { (zips, generator) -> zips.forEach { generator.generateArchive(packageConfig.project, context, it, findFiles(generator, it)) diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt index 878d0e1c..1a80ff0e 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt @@ -15,6 +15,7 @@ import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.TypeAdapter +import com.google.gson.annotations.SerializedName import com.google.gson.reflect.TypeToken import com.google.inject.assistedinject.Assisted import okhttp3.* @@ -62,7 +63,7 @@ class BintrayApi @Inject constructor(val http: Http, @Path("publish") publish: Int, @Body file: File): Call - class UpdateVersion(val desc: String?, val vcsTag: String?) + class UpdateVersion(val desc: String?, @SerializedName("vcs_tag") val vcsTag: String?) @PATCH("/packages/{owner}/maven/{repo}/versions/{version}") fun updateVersion(@Path("owner") owner: String, @@ -79,12 +80,12 @@ class BintrayApi @Inject constructor(val http: Http, // level = HttpLoggingInterceptor.Level.BASIC // }) builder.interceptors().add(Interceptor { chain -> - val original = chain.request(); + val original = chain.request() chain.proceed(original.newBuilder() .header("Authorization", Credentials.basic(username, password)) .method(original.method(), original.body()) - .build()); + .build()) }) val okHttpClient = builder.build() @@ -96,25 +97,29 @@ class BintrayApi @Inject constructor(val http: Http, .create(Api::class.java) } - fun validatePackage(project: Project) { - val execute = service.getPackage(org ?: username!!, project.name).execute() + fun validatePackage(project: Project, config: BintrayConfig) { + val pkgName = config.name ?: project.name + val execute = service.getPackage(org ?: username!!, pkgName).execute() - if (execute.errorBody()?.string()?.contains("'${project.name}' was not found") ?: false) { + if (execute.errorBody()?.string()?.contains("'$pkgName' was not found") == true) { warn("Package does not exist on bintray. Creating now.") - val result = service.createPackage(org ?: username!!, buildPackageInfo(project)) + val result = service.createPackage(org ?: username!!, buildPackageInfo(project, config)) .execute() if (result.errorBody() != null) { - throw KobaltException("Error while creating package:\n" + result.errorBody().string()) + throw KobaltException("Error while creating package:\n" + result.errorBody()!!.string()) } } } - private fun buildPackageInfo(project: Project): JsonObject { - val jsonObject = JsonObject() - jsonObject.addNonNull("name", project.name) - jsonObject.addNonNull("desc", project.description) - jsonObject.addNonNull("vcs_url", project.pom?.scm?.url) - jsonObject.addNonNull("website_url", project.url) + private fun buildPackageInfo(project: Project, config: BintrayConfig): JsonObject { + val jsonObject = JsonObject().apply { + addNonNull("name", config.name ?: project.name) + addNonNull("desc", + if (project.description.isNotBlank()) project.description else project.pom?.description) + addNonNull("vcs_url", project.pom?.scm?.url) + addNonNull("website_url", project.url ?: project.pom?.url) + addNonNull("issue_tracker_url", config.issueTrackerUrl) + } val licenses = JsonArray() project.pom?.licenses?.forEach { licenses.add(it.name) @@ -124,7 +129,7 @@ class BintrayApi @Inject constructor(val http: Http, } fun uploadMaven(project: Project, files: List, config: BintrayConfig): TaskResult { - validatePackage(project) + validatePackage(project, config) return upload(project, files, config, generateMd5 = true) } @@ -158,13 +163,13 @@ class BintrayApi @Inject constructor(val http: Http, fun dots(total: Int, list: List, file: File? = null): String { val spaces: String = Array(total - list.size, { " " }).joinToString("") - return "|" + list.map { if (it) "." else "X" }.joinToString("") + spaces + + return "|" + list.joinToString("") { if (it) "." else "X" } + spaces + (if (file != null) "| [ $file ]" else "|") } val results = arrayListOf() val owner = org ?: username!! - val repo = project.name + val repo = config.name ?: project.name val group = project.group!!.replace('.', '/') val artifact = project.artifactId!! val version = project.version!! @@ -203,7 +208,7 @@ class BintrayApi @Inject constructor(val http: Http, return TaskResult() } else { - error(" Errors while uploading:\n" + errorMessages.map { " $it" }.joinToString("\n")) + error(" Errors while uploading:\n" + errorMessages.joinToString("\n") { " $it" }) return TaskResult(false, errorMessage = errorMessages.joinToString("\n")) } } else { @@ -216,7 +221,7 @@ class BintrayApi @Inject constructor(val http: Http, fun JsonObject.addNonNull(name: String, value: String?) { if (value != null) { - addProperty(name, value); + addProperty(name, value) } } @@ -231,20 +236,16 @@ class ConverterFactory : Converter.Factory() { override fun requestBodyConverter(type: Type, parameterAnnotations: Array, methodAnnotations: Array, retrofit: Retrofit?): Converter<*, RequestBody>? { - val result = - if (type.typeName == File::class.java.name) FileBodyConverter() - else GsonBodyConverter() - return result + return if (type.typeName == File::class.java.name) FileBodyConverter() + else GsonBodyConverter() } } class GsonResponseBodyConverter(private val gson: Gson, private val adapter: TypeAdapter) : Converter { override fun convert(value: ResponseBody): Any { val jsonReader = gson.newJsonReader(value.charStream()) - try { + value.use { return adapter.read(jsonReader) - } finally { - value.close() } } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt index f5b1e4d0..c5878368 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt @@ -47,7 +47,7 @@ class PublishPlugin @Inject constructor(val files: KFiles, val factory: PomGener private fun autoGitTag(project: Project, uploadResult: TaskResult, config: AutoGitTagConfig?) : TaskResult { if (config != null) { with(config) { - return git.maybeTagRelease(project, uploadResult, enabled, annotated, tag, message) + return git.maybeTagRelease(project, uploadResult, enabled, annotated, push, tag, message) } } else { return TaskResult() @@ -117,7 +117,7 @@ class PublishPlugin @Inject constructor(val files: KFiles, val factory: PomGener val docUrl = DocUrl.PUBLISH_PLUGIN_URL val user = localProperties.get(PROPERTY_BINTRAY_USER, docUrl) val password = localProperties.get(PROPERTY_BINTRAY_PASSWORD, docUrl) - val org = localProperties.getNoThrows(PROPERTY_BINTRAY_ORG, docUrl) + val org = localProperties.getNoThrows(PROPERTY_BINTRAY_ORG) val jcenter = bintrayFactory.create(user, password, org) var success = false @@ -222,6 +222,9 @@ data class AutoGitTagConfig(val project: Project) { @Directive var annotated: Boolean = false + @Directive + var push: Boolean = true + @Directive var tag : String = project.version!! @@ -268,9 +271,18 @@ data class BintrayConfig(val project: Project) { files.add(Pair(filePath, url)) } + /** + * The package name on Bintray which is not always the project name. + */ + @Directive + var name: String? = null + @Directive var description: String? = null + @Directive + var issueTrackerUrl: String? = null + @Directive var vcsTag: String? = null } diff --git a/src/main/resources/kobalt.properties b/src/main/resources/kobalt.properties index 93253866..0d568d3c 100644 --- a/src/main/resources/kobalt.properties +++ b/src/main/resources/kobalt.properties @@ -1 +1 @@ -kobalt.version=1.0.79 +kobalt.version=1.0.122 diff --git a/src/main/resources/templates/idea/KotlinJavaRuntime.xml b/src/main/resources/templates/idea/KotlinJavaRuntime.xml index c630c0b8..3792609b 100644 --- a/src/main/resources/templates/idea/KotlinJavaRuntime.xml +++ b/src/main/resources/templates/idea/KotlinJavaRuntime.xml @@ -1,12 +1,12 @@ - + - + \ No newline at end of file diff --git a/src/test/kotlin/com/beust/kobalt/BaseTest.kt b/src/test/kotlin/com/beust/kobalt/BaseTest.kt index 51bbcf5e..3930f318 100644 --- a/src/test/kotlin/com/beust/kobalt/BaseTest.kt +++ b/src/test/kotlin/com/beust/kobalt/BaseTest.kt @@ -9,6 +9,7 @@ import com.beust.kobalt.internal.KobaltPluginXml import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.build.SingleFileBuildSources import com.beust.kobalt.misc.KFiles +import com.beust.kobalt.misc.KobaltLogger import com.beust.kobalt.misc.log import org.testng.annotations.BeforeClass import org.testng.annotations.Guice @@ -121,6 +122,9 @@ open class BaseTest(val compilerFactory: BuildFileCompiler.IFactory? = null) { val main = Kobalt.INJECTOR.getInstance(Main::class.java) val args = Args() val jc = JCommander(args).apply { parse(*commandLine) } + + KobaltLogger.setLogLevel(args) + args.buildFile = KFiles.fixSlashes(project.file.absolutePath) + "/kobalt/src/Build.kt" val result = Main.launchMain(main, jc, args, arrayOf("assemble")) return LaunchProjectResult(project, result) diff --git a/src/test/kotlin/com/beust/kobalt/VerifyKobaltZipTest.kt b/src/test/kotlin/com/beust/kobalt/VerifyKobaltZipTest.kt index 7966c8b5..d0439725 100644 --- a/src/test/kotlin/com/beust/kobalt/VerifyKobaltZipTest.kt +++ b/src/test/kotlin/com/beust/kobalt/VerifyKobaltZipTest.kt @@ -67,7 +67,7 @@ class VerifyKobaltZipTest : KobaltTest() { } else if (entry.name.endsWith("kobalt-wrapper.jar")) { val ins = zipFile.getInputStream(entry) foundWrapperJar = true - assertExistence(ins, listOf("kobalt.properties")) + assertExistence(ins, listOf("kobalt.properties", "com/beust/kobalt/wrapper/Main.class")) } entry = stream.nextEntry } diff --git a/src/test/kotlin/com/beust/kobalt/internal/KotlinCompilerVersionTest.kt b/src/test/kotlin/com/beust/kobalt/internal/KotlinCompilerVersionTest.kt new file mode 100644 index 00000000..21eb6edc --- /dev/null +++ b/src/test/kotlin/com/beust/kobalt/internal/KotlinCompilerVersionTest.kt @@ -0,0 +1,58 @@ +package com.beust.kobalt.internal + +import com.beust.kobalt.BaseTest +import com.beust.kobalt.BuildFile +import com.beust.kobalt.ProjectFile +import com.beust.kobalt.ProjectInfo +import com.beust.kobalt.misc.KFiles +import org.assertj.core.api.Assertions.assertThat +import org.testng.annotations.Test +import java.io.File + +class KotlinCompilerVersionTest : BaseTest() { + + @Test + fun shouldCompileWithExternalKotlin() { + val projectInfo = ProjectInfo( + BuildFile( + listOf("com.beust.kobalt.plugin.packaging.*", "com.beust.kobalt.plugin.kotlin.kotlinCompiler"), + """ + kotlinCompiler { + version = "1.2.60" + } + assemble{ jar{} } + """ + ), + listOf( + ProjectFile("src/main/kotlin/A.kt", "val a = Bob()"), + ProjectFile("src/main/kotlin/Bob.java", "class Bob { }") + ) + ) + + val result = launchProject(projectInfo, arrayOf("assemble", "--log", "2")) + + val project = result.projectDescription + val jarFile = File(KFiles.joinDir(project.file.absolutePath, "kobaltBuild/libs", project.name + "-" + + project.version + ".jar")) + + assertThat(jarFile).exists() + } + + @Test + fun shouldFailWhenKotlinVersionDoesNotExist() { + val projectInfo = ProjectInfo( + BuildFile( + listOf("com.beust.kobalt.plugin.packaging.*", "com.beust.kobalt.plugin.kotlin.kotlinCompiler"), + """ + kotlinCompiler { version = "1.1.20" } + assemble{ jar{} } + """ + ), + listOf(ProjectFile("src/main/kotlin/A.kt", "val a = \"foo\"")) + ) + + val result = launchProject(projectInfo, arrayOf("assemble", "--log", "2")) + + assertThat(result.result).isEqualTo(1) + } +} diff --git a/src/test/kotlin/com/beust/kobalt/misc/MavenResolverTest.kt b/src/test/kotlin/com/beust/kobalt/misc/MavenResolverTest.kt index 5b1c3458..4cee6077 100644 --- a/src/test/kotlin/com/beust/kobalt/misc/MavenResolverTest.kt +++ b/src/test/kotlin/com/beust/kobalt/misc/MavenResolverTest.kt @@ -1,5 +1,6 @@ package com.beust.kobalt.misc +import com.beust.kobalt.Args import com.beust.kobalt.BaseTest import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettingsXml @@ -95,7 +96,7 @@ class MavenResolverTest : BaseTest() { private fun resolve(id: String): List { val system = Booter.newRepositorySystem() val session = Booter.newRepositorySystemSession(system, - localRepo.localRepo, KobaltSettings(KobaltSettingsXml()), EventBus()) + localRepo.localRepo, KobaltSettings(KobaltSettingsXml()), Args(), EventBus()) val artifact = DefaultArtifact(id) val collectRequest = CollectRequest().apply {