1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-05-01 10:28:11 -07:00

Compare commits

..

No commits in common. "master" and "0.802" have entirely different histories.

241 changed files with 4674 additions and 11293 deletions

10
.gitignore vendored
View file

@ -1,15 +1,15 @@
.gradle .gradle
annotations annotations
.idea/* .idea/*
*.iml !.idea/modules.xml
nonBuildScript !.idea/libraries
!.idea/misc.xml
buildScript
kobaltBuild kobaltBuild
local.properties local.properties
classes classes
libs libs
.kobalt/ .kobalt/
./build/
out out
.DS_Store .DS_Store
lib/kotlin-*
build
.history

9
.idea/libraries/kobalt_jar.xml generated Normal file
View file

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="kobalt.jar">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/wrapper/dist/kobalt-0.789/kobalt/wrapper/kobalt-0.789.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

9
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

11
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/kobalt/Build.kt.iml" filepath="$PROJECT_DIR$/kobalt/Build.kt.iml" />
<module fileurl="file://$PROJECT_DIR$/kobalt.iml" filepath="$PROJECT_DIR$/kobalt.iml" />
<module fileurl="file://$PROJECT_DIR$/modules/kobalt-plugin-api/kobalt-plugin-api.iml" filepath="$PROJECT_DIR$/modules/kobalt-plugin-api/kobalt-plugin-api.iml" />
<module fileurl="file://$PROJECT_DIR$/modules/wrapper/kobalt-wrapper.iml" filepath="$PROJECT_DIR$/modules/wrapper/kobalt-wrapper.iml" />
</modules>
</component>
</project>

13
.travis.yml Normal file
View file

@ -0,0 +1,13 @@
cache:
directories:
- $HOME/.m2
- $HOME/.kobalt
language: java
jdk:
- oraclejdk8
install: true
script: ./kobaltw assemble test --log 1

View file

@ -1,14 +1,11 @@
# Kobalt # Kobalt [![Build Status](https://travis-ci.org/cbeust/kobalt.svg?branch=master)](https://travis-ci.org/cbeust/kobalt)
[<img src="https://teamcity.jetbrains.com/app/rest/builds/buildType:(id:OpenSourceProjects_Kobalt_Build)/statusIcon.svg">](https://teamcity.jetbrains.com/project.html?projectId=OpenSourceProjects_Kobalt&tab=projectOverview)
Kobalt is a universal build system. Kobalt is a universal build system.
To build it: To build it:
``` ```
$ ./kobaltw assemble ./kobaltw assemble
``` ```
Please see [the web site](http://beust.com/kobalt/) for the full documentation. Please see [the web site](http://beust.com/kobalt/) for the full documentation.

View file

@ -1,8 +0,0 @@
ulimit -s 1082768
#java -Xmx2048m -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $* clean
java -Xmx2048m -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $* clean assemble test --parallel

View file

@ -1,58 +0,0 @@
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'
}
}

13
dist/kobaltw vendored
View file

@ -1,11 +1,2 @@
#!/usr/bin/env sh #!/usr/bin/env bash
java -jar $(dirname $0)/../kobalt/wrapper/kobalt-wrapper.jar $*
case "$(uname)" in
CYGWIN*) DIRNAME=$(cygpath -d "$(dirname "$(readlink -f "$0")")");;
Darwin*) DIRNAME=$(dirname "$(readlink "$0")");;
*) DIRNAME=$(dirname "$(readlink -f "$0")");;
esac
if [ "$DIRNAME" = "." ]; then
DIRNAME="$(dirname "$0")"
fi
java -jar "${DIRNAME}/../kobalt/wrapper/kobalt-wrapper.jar" $*

2
dist/kobaltw.bat vendored
View file

@ -1,4 +1,2 @@
@echo off @echo off
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
java -jar "%~dp0/../kobalt/wrapper/kobalt-wrapper.jar" %* java -jar "%~dp0/../kobalt/wrapper/kobalt-wrapper.jar" %*

Binary file not shown.

View file

@ -1,5 +0,0 @@
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

188
gradlew vendored
View file

@ -1,188 +0,0 @@
#!/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" "$@"

100
gradlew.bat vendored
View file

@ -1,100 +0,0 @@
@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

377
kobalt.iml Normal file
View file

@ -0,0 +1,377 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="kobalt" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="KOBALT" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="kobalt-plugin-api" />
<orderEntry type="module-library" scope="TEST">
<library name="Kobalt: org.testng:testng:jar:6.9.10">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/testng/testng/6.9.10/testng-6.9.10.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="Kobalt: org.beanshell:bsh:jar:2.0b4">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/beanshell/bsh/2.0b4/bsh-2.0b4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="Kobalt: com.beust:jcommander:jar:1.48">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/beust/jcommander/1.48/jcommander-1.48.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="Kobalt: org.assertj:assertj-core:jar:3.4.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/assertj/assertj-core/3.4.1/assertj-core-3.4.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.inject:guice:jar:4.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/inject/guice/4.0/guice-4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: biz.aQute.bnd:bndlib:jar:2.4.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/biz/aQute/bnd/bndlib/2.4.0/bndlib-2.4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.guava:guava:jar:16.0.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/guava/guava/16.0.1/guava-16.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.retrofit2:converter-gson:jar:2.0.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/retrofit2/converter-gson/2.0.0/converter-gson-2.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.jetbrains.kotlin:kotlin-compiler-embeddable:jar:1.0.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.0.2/kotlin-compiler-embeddable-1.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-xml:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-xml/9.3.6.v20151106/jetty-xml-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.code.findbugs:jsr305:jar:3.0.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-model:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-model/3.3.9/maven-model-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: javax.inject:javax.inject:jar:1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/javax/inject/javax.inject/1/javax.inject-1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty.websocket:websocket-server:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/websocket/websocket-server/9.3.6.v20151106/websocket-server-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty.websocket:websocket-client:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/websocket/websocket-client/9.3.6.v20151106/websocket-client-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.okhttp3:okhttp:jar:3.2.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/okhttp3/okhttp/3.2.0/okhttp-3.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-servlet:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-servlet/9.3.6.v20151106/jetty-servlet-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-util:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-util/9.3.6.v20151106/jetty-util-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.okhttp3:logging-interceptor:jar:3.2.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/okhttp3/logging-interceptor/3.2.0/logging-interceptor-3.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-http:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-http/9.3.6.v20151106/jetty-http-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.beust:jcommander:jar:1.48">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/beust/jcommander/1.48/jcommander-1.48.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.retrofit2:retrofit:jar:2.0.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/retrofit2/retrofit/2.0.0/retrofit-2.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty.websocket:websocket-common:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/websocket/websocket-common/9.3.6.v20151106/websocket-common-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty.websocket:websocket-api:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/websocket/websocket-api/9.3.6.v20151106/websocket-api-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-security:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-security/9.3.6.v20151106/jetty-security-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.codehaus.plexus:plexus-utils:jar:3.0.22">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.slf4j:slf4j-api:jar:1.7.13">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/slf4j/slf4j-api/1.7.13/slf4j-api-1.7.13.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.commons:commons-lang3:jar:3.4">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.code.gson:gson:jar:2.6.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/code/gson/gson/2.6.2/gson-2.6.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty.websocket:websocket-servlet:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/websocket/websocket-servlet/9.3.6.v20151106/websocket-servlet-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.osgi:org.osgi.core:jar:4.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/osgi/org.osgi.core/4.3.1/org.osgi.core-4.3.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-webapp:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-webapp/9.3.6.v20151106/jetty-webapp-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.github.spullara.mustache.java:compiler:jar:0.9.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/github/spullara/mustache/java/compiler/0.9.1/compiler-0.9.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.sparkjava:spark-core:jar:2.5">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/sparkjava/spark-core/2.5/spark-core-2.5.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-io:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-io/9.3.6.v20151106/jetty-io-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.okio:okio:jar:1.6.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/okio/okio/1.6.0/okio-1.6.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: javax.servlet:javax.servlet-api:jar:3.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.jetty:jetty-server:jar:9.3.6.v20151106">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/jetty/jetty-server/9.3.6.v20151106/jetty-server-9.3.6.v20151106.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.inject.extensions:guice-assistedinject:jar:4.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/inject/extensions/guice-assistedinject/4.0/guice-assistedinject-4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: aopalliance:aopalliance:jar:1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module" module-name="kobalt-wrapper" />
<orderEntry type="library" name="kobalt.jar" level="project" />
</component>
</module>

12
kobalt/Build.kt.iml Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kobalt.jar" level="project" />
</component>
</module>

View file

@ -1,57 +1,35 @@
import com.beust.kobalt.* import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.License
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.api.Scm
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.homeDir
import com.beust.kobalt.plugin.application.application import com.beust.kobalt.plugin.application.application
import com.beust.kobalt.plugin.java.javaCompiler import com.beust.kobalt.plugin.java.javaCompiler
import com.beust.kobalt.plugin.kotlin.kotlinCompiler import com.beust.kobalt.plugin.kotlin.kotlinCompiler
import com.beust.kobalt.plugin.packaging.assemble import com.beust.kobalt.plugin.packaging.assemble
import com.beust.kobalt.plugin.publish.autoGitTag
import com.beust.kobalt.plugin.publish.bintray import com.beust.kobalt.plugin.publish.bintray
import com.beust.kobalt.plugin.publish.github import com.beust.kobalt.plugin.publish.github
import org.apache.maven.model.Developer import com.beust.kobalt.project
import org.apache.maven.model.License import com.beust.kobalt.test
import org.apache.maven.model.Model
import org.apache.maven.model.Scm
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
val bs = buildScript {
repos("https://dl.bintray.com/cbeust/maven")
}
object Versions { object Versions {
val kotlin = "1.2.71" val okhttp = "3.2.0"
val okhttp = "3.9.1" val okio = "1.6.0"
val okio = "1.13.0" val retrofit = "2.0.0"
val retrofit = "2.3.0" val gson = "2.6.2"
val gson = "2.8.2" val aether = "1.1.0"
val guice = "4.2.2" val sonatypeAether = "1.13.1"
val maven = "3.5.2" val maven = "3.3.9"
val mavenResolver = "1.1.0" val jersey = "2.22.2"
val slf4j = "1.7.3" val jetty = "8.1.19.v20160209" // "9.3.9.M1"
val aether = "1.0.2.v20150114"
val testng = "6.12"
val jcommander = "1.72"
// JUnit 5
val junit = "4.12"
val junitPlatform = "1.1.0"
val junitJupiter = "5.1.0"
} }
fun mavenResolver(vararg m: String)
= m.map { "org.apache.maven.resolver:maven-resolver-$it:${Versions.mavenResolver}" }
.toTypedArray()
fun aether(vararg m: String)
= m.map { "org.eclipse.aether:aether-$it:${Versions.aether}" }
.toTypedArray()
val wrapper = project { val wrapper = project {
name = "kobalt-wrapper" name = "kobalt-wrapper"
group = "com.beust" group = "com.beust"
@ -64,7 +42,6 @@ val wrapper = project {
} }
assemble { assemble {
jar { }
jar { jar {
name = projectName + ".jar" name = projectName + ".jar"
manifest { manifest {
@ -76,13 +53,6 @@ val wrapper = project {
application { application {
mainClass = "com.beust.kobalt.wrapper.Main" mainClass = "com.beust.kobalt.wrapper.Main"
} }
bintray {
publish = true
sign = true
}
pom = createPom(name, "Wrapper for Kobalt")
} }
val kobaltPluginApi = project { val kobaltPluginApi = project {
@ -92,44 +62,37 @@ val kobaltPluginApi = project {
version = readVersion() version = readVersion()
directory = "modules/kobalt-plugin-api" directory = "modules/kobalt-plugin-api"
description = "A build system in Kotlin" description = "A build system in Kotlin"
url = "https://beust.com/kobalt" url = "http://beust.com/kobalt"
licenses = listOf(License("Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0"))
pom = createPom(name, "A build system in Kotlin") scm = Scm(url = "http://github.com/cbeust/kobalt",
connection = "https://github.com/cbeust/kobalt.git",
developerConnection = "git@github.com:cbeust/kobalt.git")
dependencies { dependencies {
compile( compile("org.jetbrains.kotlinx:kotlinx.dom:0.0.10",
"org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}",
"com.google.inject:guice:${Versions.guice}", "com.google.inject:guice:4.0",
"com.google.inject.extensions:guice-assistedinject:4.1.0", "com.google.inject.extensions:guice-assistedinject:4.0",
"javax.inject:javax.inject:1", "javax.inject:javax.inject:1",
"com.google.guava:guava:27.0.1-jre", "com.google.guava:guava:19.0-rc2",
"org.apache.maven:maven-model:${Versions.maven}", "org.apache.maven:maven-model:${Versions.maven}",
"io.reactivex:rxjava:1.3.3", "io.reactivex:rxjava:1.0.16",
"com.squareup.okio:okio:${Versions.okio}",
"com.google.code.gson:gson:${Versions.gson}", "com.google.code.gson:gson:${Versions.gson}",
"com.squareup.okhttp3:okhttp:${Versions.okhttp}", "com.squareup.okio:okio:${Versions.okio}",
"com.squareup.retrofit2:retrofit:${Versions.retrofit}", "com.squareup.retrofit2:retrofit:${Versions.retrofit}",
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}", "com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
"com.beust:jcommander:${Versions.jcommander}", "com.beust:jcommander:1.48",
"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}",
"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.junitJupiter}",
"org.apache.commons:commons-compress:1.15",
"commons-io:commons-io:2.6",
// Java 9 "org.slf4j:slf4j-nop:1.6.0",
"javax.xml.bind:jaxb-api:2.3.0" "org.eclipse.aether:aether-spi:${Versions.aether}",
"org.eclipse.aether:aether-impl:${Versions.aether}",
"org.eclipse.aether:aether-connector-basic:${Versions.aether}",
"org.eclipse.aether:aether-transport-file:${Versions.aether}",
"org.eclipse.aether:aether-transport-http:${Versions.aether}",
"org.sonatype.aether:aether-api:${Versions.sonatypeAether}",
"org.sonatype.aether:aether-connector-wagon:1.13.1",
"org.apache.maven:maven-aether-provider:${Versions.maven}"
) )
exclude(*aether("impl", "spi", "util", "api"))
} }
@ -142,8 +105,12 @@ val kobaltPluginApi = project {
} }
} }
// install {
// libDir = "lib-test"
// }
kotlinCompiler { kotlinCompiler {
args("nowarn") args("-nowarn")
} }
bintray { bintray {
@ -159,35 +126,26 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
dependencies { dependencies {
// Used by the plugins // Used by the plugins
compile("org.jetbrains.kotlin:kotlin-compiler-embeddable:${Versions.kotlin}") compile("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.2")
// Used by the main app // Used by the main app
compile( compile("com.github.spullara.mustache.java:compiler:0.9.1",
"org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}",
"com.github.spullara.mustache.java:compiler:0.9.5",
"javax.inject:javax.inject:1", "javax.inject:javax.inject:1",
"com.google.inject:guice:${Versions.guice}", "com.google.inject:guice:4.0",
"com.google.inject.extensions:guice-assistedinject:${Versions.guice}", "com.google.inject.extensions:guice-assistedinject:4.0",
"com.beust:jcommander:${Versions.jcommander}", "com.beust:jcommander:1.48",
"org.apache.maven:maven-model:${Versions.maven}", "org.apache.maven:maven-model:${Versions.maven}",
"com.google.code.findbugs:jsr305:3.0.2", "com.google.code.findbugs:jsr305:3.0.1",
"com.google.code.gson:gson:${Versions.gson}", "com.google.code.gson:gson:${Versions.gson}",
"com.squareup.okhttp3:okhttp:${Versions.okhttp}",
"com.squareup.retrofit2:retrofit:${Versions.retrofit}", "com.squareup.retrofit2:retrofit:${Versions.retrofit}",
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}", "com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
// "com.squareup.okhttp3:okhttp-ws:3.4.2", "org.codehaus.plexus:plexus-utils:3.0.22",
"biz.aQute.bnd:biz.aQute.bndlib:3.5.0", "biz.aQute.bnd:bndlib:2.4.0",
*mavenResolver("spi"),
"com.squareup.okhttp3:logging-interceptor:3.9.0", "com.squareup.okhttp3:logging-interceptor:3.2.0",
"com.sparkjava:spark-core:2.6.0", "com.sparkjava:spark-core:2.5"
"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-server:${Versions.jetty}",
// "org.eclipse.jetty:jetty-servlet:${Versions.jetty}", // "org.eclipse.jetty:jetty-servlet:${Versions.jetty}",
@ -201,11 +159,8 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
} }
dependenciesTest { dependenciesTest {
compile("org.jetbrains.kotlin:kotlin-test:${Versions.kotlin}", compile("org.testng:testng:6.9.10",
"org.testng:testng:${Versions.testng}", "org.assertj:assertj-core:3.4.1")
"org.assertj:assertj-core:3.8.0",
*mavenResolver("util")
)
} }
assemble { assemble {
@ -217,27 +172,17 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
} }
zip { zip {
val dir = "kobalt-$version" val dir = "kobalt-$version"
val files = listOf( include(from("dist"), to("$dir/bin"), "kobaltw")
"dist", "$dir/bin", "kobaltw", include(from("dist"), to("$dir/bin"), "kobaltw.bat")
"dist", "$dir/bin", "kobaltw.bat", include(from("$buildDirectory/libs"), to("$dir/kobalt/wrapper"),
"$buildDirectory/libs", "$dir/kobalt/wrapper", "$projectName-$version.jar", "$projectName-$version.jar")
"modules/wrapper/$buildDirectory/libs", "$dir/kobalt/wrapper", "$projectName-wrapper.jar") include(from("modules/wrapper/$buildDirectory/libs"), to("$dir/kobalt/wrapper"),
"$projectName-wrapper.jar")
(0 .. files.size - 1 step 3).forEach { i ->
include(from(files[i]), to(files[i + 1]), files[i + 2])
}
// Package the sources
val currentDir = Paths.get(".").toAbsolutePath().normalize().toString()
zipFolders("$currentDir/$buildDirectory/libs/all-sources/$projectName-$version-sources.jar",
"$currentDir/$directory/src/main/kotlin",
"$currentDir/${kobaltPluginApi.directory}/src/main/kotlin")
include(from("$buildDirectory/libs/all-sources"), to("$dir/kobalt/wrapper"), "$projectName-$version-sources.jar")
} }
} }
kotlinCompiler { kotlinCompiler {
args("nowarn") args("-nowarn")
} }
bintray { bintray {
@ -251,32 +196,6 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
test { test {
args("-log", "2", "src/test/resources/testng.xml") args("-log", "2", "src/test/resources/testng.xml")
} }
autoGitTag {
enabled = true
}
}
fun zipFolders(zipFilePath: String, vararg foldersPath: String) {
val zip = Paths.get(zipFilePath)
Files.deleteIfExists(zip)
Files.createDirectories(zip.parent)
val zipPath = Files.createFile(zip)
ZipOutputStream(Files.newOutputStream(zipPath)).use {
foldersPath.map {Paths.get(it)}.forEach { folderPath ->
Files.walk(folderPath)
.filter { path -> !Files.isDirectory(path) }
.forEach { path ->
val zipEntry = ZipEntry(folderPath.relativize(path).toString())
try {
it.putNextEntry(zipEntry)
Files.copy(path, it)
it.closeEntry()
} catch (e: Exception) {
}
}
}
}
} }
fun readVersion() : String { fun readVersion() : String {
@ -289,38 +208,16 @@ fun readVersion() : String {
} }
} }
@Task(name = "copyVersionForWrapper", reverseDependsOn = arrayOf("assemble"), runAfter = arrayOf("clean")) @Task(name = "copyVersionForWrapper", reverseDependsOn = arrayOf("assemble"))
fun taskCopyVersionForWrapper(project: Project) : TaskResult { fun taskCopyVersionForWrapper(project: Project) : TaskResult {
if (project.name == "kobalt-wrapper") { if (project.name == "kobalt-wrapper") {
val toString = "modules/wrapper/kobaltBuild/classes" val toString = "modules/wrapper/kobaltBuild/classes"
File(toString).mkdirs() File(toString).mkdirs()
val from = Paths.get("src/main/resources/kobalt.properties") val from = Paths.get("src/main/resources/kobalt.properties")
val to = Paths.get("$toString/kobalt.properties") val to = Paths.get("$toString/kobalt.properties")
// Only copy if necessary so we don't break incremental compilation Files.copy(from,
if (! to.toFile().exists() || (from.toFile().readLines() != to.toFile().readLines())) { to,
Files.copy(from, StandardCopyOption.REPLACE_EXISTING)
to,
StandardCopyOption.REPLACE_EXISTING)
}
} }
return TaskResult() return TaskResult()
} }
fun createPom(projectName: String, projectDescription: String) = Model().apply {
name = projectName
description = projectDescription
url = "https://beust.com/kobalt"
licenses = listOf(License().apply {
name = "Apache-2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0"
})
scm = Scm().apply {
url = "https://github.com/cbeust/kobalt"
connection = "https://github.com/cbeust/kobalt.git"
developerConnection = "git@github.com:cbeust/kobalt.git"
}
developers = listOf(Developer().apply {
name = "Cedric Beust"
email = "cedric@beust.com"
})
}

Binary file not shown.

View file

@ -1 +1 @@
kobalt.version=1.0.122 kobalt.version=0.802

View file

@ -1,2 +1,2 @@
#!/usr/bin/env sh #!/usr/bin/env bash
java -jar "`dirname "$0"`/kobalt/wrapper/kobalt-wrapper.jar" $* java -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $*

View file

@ -1,8 +0,0 @@
#!/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"

View file

@ -1,4 +1,2 @@
@echo off @echo off
set DIRNAME=%~dp0 java -jar "%~dp0/kobalt/wrapper/kobalt-wrapper.jar" %*
if "%DIRNAME%" == "" set DIRNAME=.
java -jar "%DIRNAME%/kobalt/wrapper/kobalt-wrapper.jar" %*

BIN
lib/kotlin-reflect.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/kotlin-runtime.jar Normal file

Binary file not shown.

View file

@ -1,85 +0,0 @@
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'
}
}
}
}
}

View file

@ -0,0 +1,448 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="kobalt-plugin-api" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="KOBALT" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntry type="module-library">
<library name="Kobalt: org.jetbrains.kotlin:kotlin-runtime:jar:1.0.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/jetbrains/kotlin/kotlin-runtime/1.0.2/kotlin-runtime-1.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-api:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-api/1.1.0/aether-api-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.inject:guice:jar:4.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/inject/guice/4.0/guice-4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven.wagon:wagon-provider-api:jar:1.0-beta-6">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/wagon/wagon-provider-api/1.0-beta-6/wagon-provider-api-1.0-beta-6.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.aether:aether-spi:jar:1.13.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/aether/aether-spi/1.13.1/aether-spi-1.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.codehaus.plexus:plexus-component-annotations:jar:1.6">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/codehaus/plexus/plexus-component-annotations/1.6/plexus-component-annotations-1.6.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.guava:guava:jar:19.0-rc2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/guava/guava/19.0-rc2/guava-19.0-rc2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.retrofit2:converter-gson:jar:2.0.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/retrofit2/converter-gson/2.0.0/converter-gson-2.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-aether-provider:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-aether-provider/3.3.9/maven-aether-provider-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.sisu:sisu-inject-bean:jar:2.2.3">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/sisu/sisu-inject-bean/2.2.3/sisu-inject-bean-2.2.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.slf4j:jcl-over-slf4j:jar:1.6.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/slf4j/jcl-over-slf4j/1.6.2/jcl-over-slf4j-1.6.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: io.reactivex:rxjava:jar:1.0.16">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/io/reactivex/rxjava/1.0.16/rxjava-1.0.16.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.aether:aether-api:jar:1.13.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/aether/aether-api/1.13.1/aether-api-1.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-model-builder:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-model-builder/3.3.9/maven-model-builder-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-model:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-model/3.3.9/maven-model-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-spi:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-spi/1.1.0/aether-spi-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: javax.inject:javax.inject:jar:1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/javax/inject/javax.inject/1/javax.inject-1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.codehaus.plexus:plexus-classworlds:jar:2.4">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/codehaus/plexus/plexus-classworlds/2.4/plexus-classworlds-2.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.okhttp3:okhttp:jar:3.2.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/okhttp3/okhttp/3.2.0/okhttp-3.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-repository-metadata:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-repository-metadata/3.3.9/maven-repository-metadata-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.aether:aether-connector-wagon:jar:1.13.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/aether/aether-connector-wagon/1.13.1/aether-connector-wagon-1.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.slf4j:slf4j-nop:jar:1.6.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/slf4j/slf4j-nop/1.6.0/slf4j-nop-1.6.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-transport-http:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-transport-http/1.1.0/aether-transport-http-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.httpcomponents:httpclient:jar:4.3.5">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/httpcomponents/httpclient/4.3.5/httpclient-4.3.5.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-transport-file:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-transport-file/1.1.0/aether-transport-file-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.aether:aether-util:jar:1.13.1">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/aether/aether-util/1.13.1/aether-util-1.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-artifact:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-artifact/3.3.9/maven-artifact-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.sisu:sisu-guice:jar:no_aop:3.0.3">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/sisu/sisu-guice/3.0.3/sisu-guice-3.0.3-no_aop.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.beust:jcommander:jar:1.48">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/beust/jcommander/1.48/jcommander-1.48.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.maven:maven-builder-support:jar:3.3.9">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/maven/maven-builder-support/3.3.9/maven-builder-support-3.3.9.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.retrofit2:retrofit:jar:2.0.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/retrofit2/retrofit/2.0.0/retrofit-2.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.codehaus.plexus:plexus-utils:jar:3.0.22">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.httpcomponents:httpcore:jar:4.3.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.apache.commons:commons-lang3:jar:3.4">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.slf4j:slf4j-api:jar:1.6.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/slf4j/slf4j-api/1.6.2/slf4j-api-1.6.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.code.gson:gson:jar:2.6.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/code/gson/gson/2.6.2/gson-2.6.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-connector-basic:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-connector-basic/1.1.0/aether-connector-basic-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-util:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-util/1.1.0/aether-util-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.codehaus.plexus:plexus-interpolation:jar:1.21">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/codehaus/plexus/plexus-interpolation/1.21/plexus-interpolation-1.21.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.eclipse.aether:aether-impl:jar:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/eclipse/aether/aether-impl/1.1.0/aether-impl-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.squareup.okio:okio:jar:1.6.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/squareup/okio/okio/1.6.0/okio-1.6.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.sonatype.sisu:sisu-inject-plexus:jar:2.2.3">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/sonatype/sisu/sisu-inject-plexus/2.2.3/sisu-inject-plexus-2.2.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.jetbrains.kotlin:kotlin-stdlib:jar:1.0.2">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/jetbrains/kotlin/kotlin-stdlib/1.0.2/kotlin-stdlib-1.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: commons-logging:commons-logging:jar:1.1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: org.jetbrains.kotlinx:kotlinx.dom:jar:0.0.10">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/org/jetbrains/kotlinx/kotlinx.dom/0.0.10/kotlinx.dom-0.0.10.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: com.google.inject.extensions:guice-assistedinject:jar:4.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/com/google/inject/extensions/guice-assistedinject/4.0/guice-assistedinject-4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: aopalliance:aopalliance:jar:1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Kobalt: commons-codec:commons-codec:jar:1.6">
<CLASSES>
<root url="jar://$USER_HOME$/.kobalt/repository/commons-codec/commons-codec/1.6/commons-codec-1.6.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="kobalt.jar" level="project" />
</component>
</module>

View file

@ -1,279 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.beust</groupId>
<artifactId>kobalt-pom</artifactId>
<version>1.1.0</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>kobalt-plugin-api</artifactId>
<packaging>jar</packaging>
<version>1.1.0</version>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-aether-provider</artifactId>
<version>3.3.9</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.aether</groupId>
<artifactId>impl</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.aether</groupId>
<artifactId>spi</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.aether</groupId>
<artifactId>util</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.aether</groupId>
<artifactId>api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-api</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-spi</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-impl</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-http</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-file</artifactId>
<version>${mavenresolver.version}</version>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>${okio.version}</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.72</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>2.4.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junitJupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junitJupiter.version}</version>
</dependency>
<dependency>
<groupId>org.testng.testng-remote</groupId>
<artifactId>testng-remote</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>4.9.0.201710071750-r</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- java 9 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals> <goal>testCompile</goal> </goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,21 +0,0 @@
package com.beust.kobalt
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.archive.Zip
import com.beust.kobalt.misc.KFiles
import java.io.File
interface ArchiveGenerator {
fun findIncludedFiles(project: Project, context: KobaltContext, zip: Zip) : List<IncludedFile>
val suffix: String
fun generateArchive(project: Project, context: KobaltContext, zip: Zip, files: List<IncludedFile>) : File
fun fullArchiveName(project: Project, context: KobaltContext, archiveName: String?) : File {
val fullArchiveName = context.variant.archiveName(project, archiveName, suffix)
val archiveDir = File(KFiles.libsDir(project))
val result = File(archiveDir.path, fullArchiveName)
return result
}
}

View file

@ -7,7 +7,7 @@ class Args {
var targets: List<String> = arrayListOf() var targets: List<String> = arrayListOf()
@Parameter(names = arrayOf("-bf", "--buildFile"), description = "The build file") @Parameter(names = arrayOf("-bf", "--buildFile"), description = "The build file")
var buildFile: String? = "kobalt/src/Build.kt" var buildFile: String? = null
@Parameter(names = arrayOf("--checkVersions"), description = "Check if there are any newer versions of the " + @Parameter(names = arrayOf("--checkVersions"), description = "Check if there are any newer versions of the " +
"dependencies") "dependencies")
@ -22,10 +22,6 @@ class Args {
@Parameter(names = arrayOf("--download"), description = "Force a download from the downloadUrl in the wrapper") @Parameter(names = arrayOf("--download"), description = "Force a download from the downloadUrl in the wrapper")
var download: Boolean = false var download: Boolean = false
@Parameter(names = arrayOf("--downloadSources"),
description = "Force a download of sources and javadocs when resolving dependencies")
var downloadSources: Boolean = false
@Parameter(names = arrayOf("--dryRun"), description = "Display all the tasks that will get run without " + @Parameter(names = arrayOf("--dryRun"), description = "Display all the tasks that will get run without " +
"actually running them") "actually running them")
var dryRun: Boolean = false var dryRun: Boolean = false
@ -46,13 +42,8 @@ class Args {
@Parameter(names = arrayOf("--listTemplates"), description = "List the available templates") @Parameter(names = arrayOf("--listTemplates"), description = "List the available templates")
var listTemplates: Boolean = false var listTemplates: Boolean = false
@Parameter(names = arrayOf("--log"), description = "Define the log level " + @Parameter(names = arrayOf("--log"), description = "Define the log level (1-3)")
"(${Constants.LOG_QUIET_LEVEL}-${Constants.LOG_MAX_LEVEL})") var log: Int = 1
var log: Int = Constants.LOG_DEFAULT_LEVEL
@Parameter(names = arrayOf("--logTags"),
description = "Comma-separated list of tags to enable logging for")
var logTags: String = ""
@Parameter(names = arrayOf("--forceIncremental"), @Parameter(names = arrayOf("--forceIncremental"),
description = "Force the build to be incremental even if the build file was modified") description = "Force the build to be incremental even if the build file was modified")
@ -61,9 +52,6 @@ class Args {
@Parameter(names = arrayOf("--noIncremental"), description = "Turn off incremental builds") @Parameter(names = arrayOf("--noIncremental"), description = "Turn off incremental builds")
var noIncremental: Boolean = false 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") @Parameter(names = arrayOf("--plugins"), description = "Comma-separated list of plug-in Maven id's")
var pluginIds: String? = null var pluginIds: String? = null
@ -76,26 +64,13 @@ class Args {
@Parameter(names = arrayOf("--profiles"), description = "Comma-separated list of profiles to run") @Parameter(names = arrayOf("--profiles"), description = "Comma-separated list of profiles to run")
var profiles: String? = null var profiles: String? = null
@Parameter(names = arrayOf("--profiling"), description = "Display task timings at the end of the build")
var profiling: Boolean = false
@Parameter(names = arrayOf("--resolve"), @Parameter(names = arrayOf("--resolve"),
description = "Resolve the given dependency and display its tree") description = "Resolve the given comma-separated dependencies and display their dependency tree")
var dependency: String? = null var dependencies: String? = null
@Parameter(names = arrayOf("--projectInfo"), description = "Display information about the current projects") @Parameter(names = arrayOf("--projectInfo"), description = "Display information about the current projects")
var projectInfo: Boolean = false var projectInfo: Boolean = false
@Parameter(names = arrayOf("--noIncrementalKotlin"), description = "Disable incremental Kotlin compilation")
var noIncrementalKotlin: Boolean = false
companion object {
const val SEQUENTIAL = "--sequential"
}
@Parameter(names = arrayOf(Args.SEQUENTIAL), description = "Build all the projects in sequence")
var sequential: Boolean = false
@Parameter(names = arrayOf("--server"), description = "Run in server mode") @Parameter(names = arrayOf("--server"), description = "Run in server mode")
var serverMode: Boolean = false var serverMode: Boolean = false
@ -104,8 +79,5 @@ class Args {
@Parameter(names = arrayOf("--update"), description = "Update to the latest version of Kobalt") @Parameter(names = arrayOf("--update"), description = "Update to the latest version of Kobalt")
var update: Boolean = false var update: Boolean = false
@Parameter(names = arrayOf("--version"), description = "Display the current version of Kobalt")
var version: Boolean = false
} }

View file

@ -1,32 +1,23 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.kobalt.misc.log
import java.util.* import java.util.*
/**
* Make Kobalt's output awesome and unique.
*
* I spend so much time staring at build outputs I decided I might as well make them pretty.
* Note that I also experimented with colors but it's hard to come up with a color scheme that
* will work with all the various backgrounds developers use, so I decided to be conservative
* and stick to simple red/yellow for errors and warnings.
*
* @author Cedric Beust <cedric@beust.com>
* @since 10/1/2015
*/
class AsciiArt { class AsciiArt {
companion object { companion object {
private val BANNERS = arrayOf( private val BANNERS = arrayOf(
" __ __ __ __ __ \n" + " __ __ __ __ __ \n" +
" / //_/ ____ / /_ ____ _ / / / /_\n" + " / //_/ ____ / /_ ____ _ / / / /_\n" +
" / ,< / __ \\ / __ \\ / __ `/ / / / __/\n" + " / ,< / __ \\ / __ \\ / __ `/ / / / __/\n" +
" / /| | / /_/ / / /_/ // /_/ / / / / /_ \n" + " / /| | / /_/ / / /_/ // /_/ / / / / /_ \n" +
" /_/ |_| \\____/ /_.___/ \\__,_/ /_/ \\__/ ", " /_/ |_| \\____/ /_.___/ \\__,_/ /_/ \\__/ ",
" _ __ _ _ _ \n" + " _ __ _ _ _ \n" +
" | |/ / ___ | |__ __ _ | | | |_ \n" + " | |/ / ___ | |__ __ _ | | | |_ \n" +
" | ' / / _ \\ | '_ \\ / _` | | | | __|\n" + " | ' / / _ \\ | '_ \\ / _` | | | | __|\n" +
" | . \\ | (_) | | |_) | | (_| | | | | |_ \n" + " | . \\ | (_) | | |_) | | (_| | | | | |_ \n" +
" |_|\\_\\ \\___/ |_.__/ \\__,_| |_| \\__| " " |_|\\_\\ \\___/ |_.__/ \\__,_| |_| \\__| "
) )
val banner : String get() = BANNERS[Random().nextInt(BANNERS.size)] val banner : String get() = BANNERS[Random().nextInt(BANNERS.size)]
@ -35,59 +26,47 @@ class AsciiArt {
val horizontalSingleLine = "\u2500\u2500\u2500\u2500\u2500" val horizontalSingleLine = "\u2500\u2500\u2500\u2500\u2500"
val horizontalDoubleLine = "\u2550\u2550\u2550\u2550\u2550" val horizontalDoubleLine = "\u2550\u2550\u2550\u2550\u2550"
val verticalBar = "\u2551"
// fun horizontalLine(n: Int) = StringBuffer().apply { // fun horizontalLine(n: Int) = StringBuffer().apply {
// repeat(n, { append("\u2500") }) // repeat(n, { append("\u2500") })
// }.toString() // }.toString()
// Repeat fun box(strings: List<String>) : List<String> {
fun r(n: Int, w: String) : String { val ul = "\u2554"
with(StringBuffer()) { val ur = "\u2557"
repeat(n, { append(w) }) val h = "\u2550"
return toString() val v = "\u2551"
val bl = "\u255a"
val br = "\u255d"
fun r(n: Int, w: String) : String {
with(StringBuffer()) {
repeat(n, { append(w) })
return toString()
}
} }
}
val h = "\u2550"
val ul = "\u2554"
val ur = "\u2557"
val bottomLeft = "\u255a"
val bottomRight = "\u255d"
// Bottom left with continuation
val bottomLeft2 = "\u2560"
// Bottom right with continuation
val bottomRight2 = "\u2563"
fun upperBox(max: Int) = ul + r(max + 2, h) + ur
fun lowerBox(max: Int, bl: String = bottomLeft, br : String = bottomRight) = bl + r(max + 2, h) + br
private fun box(strings: List<String>, bl: String = bottomLeft, br: String = bottomRight) : List<String> {
val v = verticalBar
val maxString: String = strings.maxBy { it.length } ?: "" val maxString: String = strings.maxBy { it.length } ?: ""
val max = maxString.length val max = maxString.length
val result = arrayListOf(upperBox(max)) val result = arrayListOf(ul + r(max + 2, h) + ur)
result.addAll(strings.map { "$v ${center(it, max - 2)} $v" }) result.addAll(strings.map { "$v ${center(it, max - 2)} $v" })
result.add(lowerBox(max, bl, br)) result.add(bl + r(max + 2, h) + br)
return result return result
} }
fun logBox(strings: List<String>, bl: String = bottomLeft, br: String = bottomRight, indent: Int = 0): String { private fun fill(n: Int) = StringBuffer().apply { repeat(n, { append(" ")})}.toString()
return buildString {
val boxLines = box(strings, bl, br) val defaultLog : (s: String) -> Unit = { log(1, " $it") }
boxLines.withIndex().forEach { iv ->
append(fill(indent)).append(iv.value) fun logBox(strings: List<String>, print: (String) -> Unit = defaultLog) {
if (iv.index < boxLines.size - 1) append("\n") box(strings).forEach {
} print(it)
} }
} }
fun logBox(s: String, bl: String = bottomLeft, br: String = bottomRight, indent: Int = 0) fun logBox(s: String, print: (String) -> Unit = defaultLog) {
= logBox(listOf(s), bl, br, indent) logBox(listOf(s), print)
}
fun fill(n: Int) = buildString { repeat(n, { append(" ")})}.toString()
fun center(s: String, width: Int) : String { fun center(s: String, width: Int) : String {
val diff = width - s.length val diff = width - s.length
@ -105,60 +84,14 @@ class AsciiArt {
const val CYAN = "\u001B[36m" const val CYAN = "\u001B[36m"
const val WHITE = "\u001B[37m" const val WHITE = "\u001B[37m"
fun wrap(s: CharSequence, color: String) = color + s + RESET private fun wrap(s: String, color: String) = color + s + RESET
private fun blue(s: CharSequence) = wrap(s, BLUE) private fun blue(s: String) = wrap(s, BLUE)
private fun red(s: CharSequence) = wrap(s, RED) private fun red(s: String) = wrap(s, RED)
private fun yellow(s: CharSequence) = wrap(s, YELLOW) private fun yellow(s: String) = wrap(s, YELLOW)
fun taskColor(s: CharSequence) = s fun taskColor(s: String) = s
fun errorColor(s: CharSequence) = red(s) fun errorColor(s: String) = red(s)
fun warnColor(s: CharSequence) = red(s) fun warnColor(s: String) = red(s)
} }
} }
class AsciiTable {
class Builder {
private val headers = arrayListOf<String>()
fun header(name: String) = headers.add(name)
fun headers(vararg names: String) = headers.addAll(names)
private val widths = arrayListOf<Int>()
fun columnWidth(w: Int) : Builder {
widths.add(w)
return this
}
private val rows = arrayListOf<List<String>>()
fun addRow(row: List<String>) = rows.add(row)
private fun col(width: Int, s: String) : String {
val format = " %1\$-${width.toString()}s"
val result = String.format(format, s)
return result
}
val vb = AsciiArt.verticalBar
fun build() : String {
val formattedHeaders =
headers.mapIndexed { index, s ->
val s2 = col(widths[index], s)
s2
}.joinToString(vb)
val result = StringBuffer().apply {
append(AsciiArt.logBox(formattedHeaders, AsciiArt.bottomLeft2, AsciiArt.bottomRight2))
append("\n")
}
var lineLength = 0
rows.forEachIndexed { _, row ->
val formattedRow = row.mapIndexed { i, s -> col(widths[i], s) }.joinToString(vb)
val line = "$vb $formattedRow $vb"
result.append(line).append("\n")
lineLength = line.length
}
result.append(AsciiArt.lowerBox(lineLength - 4))
return result.toString()
}
}
}

View file

@ -3,89 +3,42 @@ package com.beust.kobalt
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.dependency.FileDependency import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KobaltLogger
import org.eclipse.aether.repository.Proxy import org.eclipse.aether.repository.Proxy
import java.io.File import java.io.File
import java.net.InetSocketAddress import java.net.InetSocketAddress
var BUILD_SCRIPT_CONFIG : BuildScriptConfig? = null
class BuildScriptConfig {
/** The list of repos used to locate plug-ins. */
@Directive
fun repos(vararg r: String) = newRepos(*r)
/** The list of plug-ins to use for this build file. */
@Directive
fun plugins(vararg pl: String) = newPlugins(*pl)
/** The build file classpath. */
@Directive
fun buildFileClasspath(vararg bfc: String) = newBuildFileClasspath(*bfc)
/** Options passed to Kobalt */
@Directive
fun kobaltOptions(vararg options: String) = Kobalt.addKobaltOptions(options)
/** Where to find additional build files */
@Directive
fun buildSourceDirs(vararg dirs: String) = Kobalt.addBuildSourceDirs(dirs)
// The following settings modify the compiler used to compile the build file, which regular users should
// probably never need to do. Projects should use kotlinCompiler { compilerVersion } to configure the
// Kotin compiler for their source files.
var kobaltCompilerVersion : String? = null
var kobaltCompilerRepo: String? = null
var kobaltCompilerFlags: String? = null
}
@Directive @Directive
fun homeDir(vararg dirs: String) : String = SystemProperties.homeDir + fun homeDir(vararg dirs: String) : String = SystemProperties.homeDir +
File.separator + dirs.toMutableList().joinToString(File.separator) File.separator + dirs.toMutableList().joinToString(File.separator)
@Directive
fun localMavenRepo() = homeDir(".m2" + File.separator + "repository/")
@Directive @Directive
fun file(file: String) : String = FileDependency.PREFIX_FILE + file fun file(file: String) : String = FileDependency.PREFIX_FILE + file
@Directive
fun plugins(vararg dependency : IClasspathDependency) { fun plugins(vararg dependency : IClasspathDependency) {
dependency.forEach { Plugins.addDynamicPlugin(it) } dependency.forEach { Plugins.addDynamicPlugin(it) }
} }
fun plugins(vararg dependencies : String) {
KobaltLogger.logger.warn("Build.kt",
"Invoking plugins() directly is deprecated, use the buildScript{} directive")
newPlugins(*dependencies)
}
@Directive @Directive
fun newPlugins(vararg dependencies : String) { fun plugins(vararg dependencies : String) {
val factory = Kobalt.INJECTOR.getInstance(DependencyManager::class.java) val factory = Kobalt.INJECTOR.getInstance(DependencyManager::class.java)
dependencies.forEach { dependencies.forEach {
Plugins.addDynamicPlugin(factory.create(it)) Plugins.addDynamicPlugin(factory.create(it))
} }
} }
data class ProxyConfig(val host: String = "", val port: Int = 0, val type: String = "", val nonProxyHosts: String = "") { data class ProxyConfig(var host: String = "", var port: Int = 0, val type: String = "") {
fun toProxy() = java.net.Proxy(java.net.Proxy.Type.HTTP, InetSocketAddress(host, port)) fun toProxy() = java.net.Proxy(java.net.Proxy.Type.HTTP, InetSocketAddress(host, port))
fun toAetherProxy() = Proxy(type, host, port) // TODO make support for proxy auth fun toAetherProxy() = Proxy(type, host, port) // TODO make support for proxy auth
} }
data class HostConfig(var url: String = "", var name: String = HostConfig.createRepoName(url), data class HostConfig(var url: String = "", var username: String? = null, var password: String? = null) {
var username: String? = null, var password: String? = null) {
companion object {
/**
* For repos specified in the build file (repos()) that don't have an associated unique name,
* create such a name from the URL. This is a requirement from Maven Resolver, and failing to do
* this leads to very weird resolution errors.
*/
private fun createRepoName(url: String) = url.replace("/", "_").replace("\\", "_").replace(":", "_")
}
fun hasAuth() : Boolean { fun hasAuth() : Boolean {
return (! username.isNullOrBlank()) && (! password.isNullOrBlank()) return (! username.isNullOrBlank()) && (! password.isNullOrBlank())
} }
@ -99,47 +52,18 @@ data class HostConfig(var url: String = "", var name: String = HostConfig.create
} }
} }
@Directive
fun repos(vararg repos : String) { fun repos(vararg repos : String) {
KobaltLogger.logger.warn("Build.kt",
"Invoking repos() directly is deprecated, use the buildScript{} directive")
newRepos(*repos)
}
fun newRepos(vararg repos: String) {
repos.forEach { Kobalt.addRepo(HostConfig(it)) } repos.forEach { Kobalt.addRepo(HostConfig(it)) }
} }
fun buildFileClasspath(vararg deps: String) {
KobaltLogger.logger.warn("Build.kt",
"Invoking buildFileClasspath() directly is deprecated, use the buildScript{} directive")
newBuildFileClasspath(*deps)
}
fun newBuildFileClasspath(vararg deps: String) {
//FIXME newBuildFileClasspath called twice
deps.forEach { Kobalt.addBuildFileClasspath(it) }
}
@Directive @Directive
fun authRepos(vararg repos : HostConfig) { fun authRepos(vararg repos : HostConfig) {
repos.forEach { Kobalt.addRepo(it) } repos.forEach { Kobalt.addRepo(it) }
} }
@Directive @Directive
fun authRepo(init: HostConfig.() -> Unit) = HostConfig(name = "").apply { init() } fun authRepo(init: HostConfig.() -> Unit) = HostConfig().apply { init() }
@Directive @Directive
fun glob(g: String) : IFileSpec.GlobSpec = IFileSpec.GlobSpec(g) fun glob(g: String) : IFileSpec.GlobSpec = IFileSpec.GlobSpec(g)
/**
* The location of the local Maven repository.
*/
@Directive
fun localMaven() : String {
val pluginInfo = Kobalt.INJECTOR.getInstance(PluginInfo::class.java)
val initial = Kobalt.INJECTOR.getInstance(KobaltSettings::class.java).localMavenRepo
val result = pluginInfo.localMavenRepoPathInterceptors.fold(initial) { current, interceptor ->
File(interceptor.repoPath(current.absolutePath))
}
return result.toURI().toString()
}

View file

@ -3,19 +3,15 @@ package com.beust.kobalt
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
object Constants { object Constants {
const val LOG_QUIET_LEVEL = 0
const val LOG_DEFAULT_LEVEL = 1
const val LOG_MAX_LEVEL = 3
val BUILD_FILE_NAME = "Build.kt" val BUILD_FILE_NAME = "Build.kt"
val BUILD_FILE_DIRECTORY = "kobalt/src" val BUILD_FILE_DIRECTORY = "kobalt/src"
val BUILD_FILE_PATH = KFiles.joinDir(BUILD_FILE_DIRECTORY, BUILD_FILE_NAME) val BUILD_FILE_PATH = KFiles.joinDir(BUILD_FILE_DIRECTORY, BUILD_FILE_NAME)
val KOTLIN_COMPILER_VERSION = "1.2.70"
internal val DEFAULT_REPOS = listOf<HostConfig>( internal val DEFAULT_REPOS = listOf<String>(
// "https://maven-central.storage.googleapis.com/", // "https://maven-central.storage.googleapis.com/",
HostConfig("https://repo1.maven.org/maven2/", "Maven"), "http://repo1.maven.org/maven2/",
HostConfig("https://jcenter.bintray.com/", "JCenter") "https://jcenter.bintray.com/",
// "https://repository.jetbrains.com/all/", // <-- contains snapshots "http://repository.jetbrains.com/all/"
// snapshots // snapshots
// "https://oss.sonatype.org/content/repositories/snapshots/" // "https://oss.sonatype.org/content/repositories/snapshots/"

View file

@ -4,11 +4,9 @@ import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.JvmCompilerPlugin import com.beust.kobalt.internal.JvmCompilerPlugin
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@Directive @Directive
fun project(vararg projects: Project, init: Project.() -> Unit): Project { public fun project(vararg projects: Project, init: Project.() -> Unit): Project {
return Project("").apply { return Project("").apply {
init() init()
(Kobalt.findPlugin(JvmCompilerPlugin.PLUGIN_NAME) as JvmCompilerPlugin) (Kobalt.findPlugin(JvmCompilerPlugin.PLUGIN_NAME) as JvmCompilerPlugin)
@ -16,24 +14,3 @@ fun project(vararg projects: Project, init: Project.() -> Unit): Project {
} }
} }
@Directive
fun buildScript(init: BuildScriptConfig.() -> Unit): BuildScriptConfig {
val buildScriptConfig = BuildScriptConfig().apply { init() }
BUILD_SCRIPT_CONFIG = buildScriptConfig
return buildScriptConfig
}
@Directive
fun profile(): ReadWriteProperty<Nothing?, Boolean> {
val result = object: ReadWriteProperty<Nothing?, Boolean> {
var value: Boolean = false
override operator fun getValue(thisRef: Nothing?, property: KProperty<*>): Boolean {
return value
}
override operator fun setValue(thisRef: Nothing?, property: KProperty<*>, value: Boolean) {
this.value = value
}
}
return result
}

View file

@ -1,6 +1,6 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import java.io.File import java.io.File
import java.nio.file.* import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
@ -28,15 +28,15 @@ sealed class IFileSpec {
private fun isIncluded(includeMatchers: Glob, excludes: List<Glob>, rel: Path) : Boolean { private fun isIncluded(includeMatchers: Glob, excludes: List<Glob>, rel: Path) : Boolean {
excludes.forEach { excludes.forEach {
if (it.matches(rel)) { if (it.matches(rel)) {
kobaltLog(3, " Excluding ${rel.toFile()}") log(3, "Excluding ${rel.toFile()}")
return false return false
} }
} }
if (includeMatchers.matches(rel)) { if (includeMatchers.matches(rel)) {
kobaltLog(3, " Including ${rel.toFile().path}") log(3, "Including ${rel.toFile().path}")
return true return true
} }
kobaltLog(2, " Excluding ${rel.toFile()} (not matching any include pattern") log(2, "Excluding ${rel.toFile()} (not matching any include pattern")
return false return false
} }
@ -56,7 +56,7 @@ sealed class IFileSpec {
val path = p.normalize() val path = p.normalize()
val rel = orgRootDir.relativize(path) val rel = orgRootDir.relativize(path)
if (isIncluded(includes, excludes, path)) { if (isIncluded(includes, excludes, path)) {
kobaltLog(3, " including file " + rel.toFile() + " from rootDir $rootDir") log(3, " including file " + rel.toFile() + " from rootDir $rootDir")
result.add(rel.toFile()) result.add(rel.toFile())
} }
return FileVisitResult.CONTINUE return FileVisitResult.CONTINUE

View file

@ -1,43 +0,0 @@
package com.beust.kobalt
import com.beust.kobalt.api.annotation.Directive
import java.io.File
/**
* Base classes for directives that support install(from,to) (e.g. install{} or jar{}).
*/
open class IncludeFromTo {
/**
* Prefix path to be removed from the zip file. For example, if you add "build/lib/a.jar" to the zip
* file and the excludePrefix is "build/lib", then "a.jar" will be added at the root of the zip file.
*/
val includedFiles = arrayListOf<IncludedFile>()
@Directive
fun from(s: String) = From(s)
@Directive
fun to(s: String) = To(s)
@Directive
fun copy(from: From, to: To) {
val dir = File(from.path).absoluteFile.parentFile
includedFiles.add(IncludedFile(from(dir.absolutePath), to, listOf(IFileSpec.FileSpec(from.path))))
}
@Directive
fun include(vararg files: String) {
includedFiles.add(IncludedFile(files.map { IFileSpec.FileSpec(it) }))
}
@Directive
fun include(from: From, to: To, vararg specs: String) {
includedFiles.add(IncludedFile(from, to, specs.map { IFileSpec.FileSpec(it) }))
}
@Directive
fun include(from: From, to: To, vararg specs: IFileSpec.GlobSpec) {
includedFiles.add(IncludedFile(from, to, listOf(*specs)))
}
}

View file

@ -1,44 +0,0 @@
package com.beust.kobalt
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.toString
import java.io.File
import java.nio.file.Paths
class IncludedFile(val fromOriginal: From, val toOriginal: To, val specs: List<IFileSpec>,
val expandJarFiles: Boolean = false) {
constructor(specs: List<IFileSpec>, expandJarFiles: Boolean = false) : this(From(""), To(""), specs, expandJarFiles)
fun from(s: String) = File(if (fromOriginal.isCurrentDir()) s else KFiles.joinDir(from, s))
val from: String get() = fromOriginal.path.replace("\\", "/")
fun to(s: String) = File(if (toOriginal.isCurrentDir()) s else KFiles.joinDir(to, s))
val to: String get() = toOriginal.path.replace("\\", "/")
override fun toString() = toString("IncludedFile",
"files - ", specs.map { it.toString() },
"from", from,
"to", to)
fun allFromFiles(directory: String? = null): List<File> {
val result = arrayListOf<File>()
specs.forEach { spec ->
// val fullDir = if (directory == null) from else KFiles.joinDir(directory, from)
spec.toFiles(directory, from).forEach { source ->
result.add(if (source.isAbsolute) source else File(source.path))
}
}
return result.map { Paths.get(it.path).normalize().toFile()}
}
}
open class Direction(open val p: String) {
override fun toString() = path
fun isCurrentDir() = path == "./"
val path: String get() =
if (p.isEmpty()) "./"
else if (p.startsWith("/") || p.endsWith("/")) p
else p + "/"
}
class From(override val p: String) : Direction(p)
class To(override val p: String) : Direction(p)

View file

@ -3,22 +3,18 @@ package com.beust.kobalt
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.archive.Archives import com.beust.kobalt.archive.Archives
import com.beust.kobalt.archive.MetaArchive import com.beust.kobalt.archive.Jar
import com.beust.kobalt.archive.Zip
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.misc.*
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import com.google.inject.Inject import com.google.inject.Inject
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.OutputStream
import java.nio.file.Paths import java.nio.file.Paths
import java.util.jar.Manifest import java.util.jar.JarOutputStream
class JarGenerator @Inject constructor(val dependencyManager: DependencyManager) : ArchiveGenerator { class JarGenerator @Inject constructor(val dependencyManager: DependencyManager) {
companion object { companion object {
fun findIncludedFiles(directory: String, files: List<IncludedFile>, excludes: List<Glob>, fun findIncludedFiles(directory: String, files: List<IncludedFile>, excludes: List<Glob>)
throwOnError: Boolean = true)
: List<IncludedFile> { : List<IncludedFile> {
val result = arrayListOf<IncludedFile>() val result = arrayListOf<IncludedFile>()
files.forEach { includedFile -> files.forEach { includedFile ->
@ -28,7 +24,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
if (File(directory, fromPath).exists()) { if (File(directory, fromPath).exists()) {
spec.toFiles(directory, fromPath).forEach { file -> spec.toFiles(directory, fromPath).forEach { file ->
val fullFile = File(KFiles.joinDir(directory, fromPath, file.path)) val fullFile = File(KFiles.joinDir(directory, fromPath, file.path))
if (! fullFile.exists() && throwOnError) { if (! fullFile.exists()) {
throw AssertionError("File should exist: $fullFile") throw AssertionError("File should exist: $fullFile")
} }
@ -36,16 +32,16 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
val normalized = Paths.get(file.path).normalize().toFile().path val normalized = Paths.get(file.path).normalize().toFile().path
includedSpecs.add(IFileSpec.FileSpec(normalized)) includedSpecs.add(IFileSpec.FileSpec(normalized))
} else { } else {
kobaltLog(2, "Not adding ${file.path} to jar file because it's excluded") log(2, "Not adding ${file.path} to jar file because it's excluded")
} }
} }
} else { } else {
kobaltLog(2, " Directory $fromPath doesn't exist, not including it in the jar") log(2, "Directory $fromPath doesn't exist, not including it in the jar")
} }
} }
if (includedSpecs.size > 0) { if (includedSpecs.size > 0) {
kobaltLog(3, "Including specs $includedSpecs") log(3, "Including specs $includedSpecs")
result.add(IncludedFile(From(includedFile.from), To(includedFile.to), includedSpecs)) result.add(IncludedFile(From(includedFile.from), To(includedFile.to), includedSpecs))
} }
} }
@ -53,9 +49,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
} }
} }
override val suffix = ".jar" fun findIncludedFiles(project: Project, context: KobaltContext, jar: Jar) : List<IncludedFile> {
override fun findIncludedFiles(project: Project, context: KobaltContext, zip: Zip) : List<IncludedFile> {
// //
// Add all the applicable files for the current project // Add all the applicable files for the current project
// //
@ -63,7 +57,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
val result = arrayListOf<IncludedFile>() val result = arrayListOf<IncludedFile>()
val classesDir = KFiles.makeDir(buildDir.path, "classes") val classesDir = KFiles.makeDir(buildDir.path, "classes")
if (zip.includedFiles.isEmpty()) { if (jar.includedFiles.isEmpty()) {
// If no includes were specified, assume the user wants a simple jar file made of the // If no includes were specified, assume the user wants a simple jar file made of the
// classes of the project, so we specify a From("build/classes/"), To("") and // classes of the project, so we specify a From("build/classes/"), To("") and
// a list of files containing everything under it // a list of files containing everything under it
@ -73,7 +67,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
// Class files // Class files
val files = KFiles.findRecursively(classesDir).map { File(relClassesDir.toFile(), it) } val files = KFiles.findRecursively(classesDir).map { File(relClassesDir.toFile(), it) }
val filesNotExcluded : List<File> = files.filter { val filesNotExcluded : List<File> = files.filter {
! KFiles.Companion.isExcluded(KFiles.joinDir(project.directory, it.path), zip.excludes) ! KFiles.Companion.isExcluded(KFiles.joinDir(project.directory, it.path), jar.excludes)
} }
val fileSpecs = arrayListOf<IFileSpec>() val fileSpecs = arrayListOf<IFileSpec>()
filesNotExcluded.forEach { filesNotExcluded.forEach {
@ -89,14 +83,16 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
// //
// The user specified an include, just use it verbatim // The user specified an include, just use it verbatim
// //
val includedFiles = findIncludedFiles(project.directory, zip.includedFiles, zip.excludes, false) val includedFiles = findIncludedFiles(project.directory, jar.includedFiles, jar.excludes)
result.addAll(includedFiles) result.addAll(includedFiles)
} }
// //
// If fatJar is true, add all the transitive dependencies as well: compile, runtime and dependent projects // If fatJar is true, add all the transitive dependencies as well: compile, runtime and dependent projects
// //
if (zip.fatJar) { if (jar.fatJar) {
log(2, "Creating fat jar")
val seen = hashSetOf<String>() val seen = hashSetOf<String>()
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val allDependencies = project.compileDependencies + project.compileRuntimeDependencies + val allDependencies = project.compileDependencies + project.compileRuntimeDependencies +
@ -104,15 +100,14 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
context.variant.buildType.compileRuntimeDependencies + context.variant.buildType.compileRuntimeDependencies +
context.variant.productFlavor.compileDependencies + context.variant.productFlavor.compileDependencies +
context.variant.productFlavor.compileRuntimeDependencies context.variant.productFlavor.compileRuntimeDependencies
val transitiveDependencies = dependencyManager.calculateDependencies(project, context, val transitiveDependencies = dependencyManager.calculateDependencies(project, context, allDependencies)
scopes = listOf(Scope.COMPILE), passedDependencies = allDependencies)
transitiveDependencies.map { transitiveDependencies.map {
it.jarFile.get() it.jarFile.get()
}.forEach { file : File -> }.forEach { file : File ->
if (! seen.contains(file.path)) { if (! seen.contains(file.path)) {
seen.add(file.path) seen.add(file.path)
if (! KFiles.Companion.isExcluded(file, zip.excludes)) { if (! KFiles.Companion.isExcluded(file, jar.excludes)) {
result.add(IncludedFile(specs = arrayListOf(IFileSpec.FileSpec(file.absolutePath)), result.add(IncludedFile(specs = arrayListOf(IFileSpec.FileSpec(file.path)),
expandJarFiles = true)) expandJarFiles = true))
} }
} }
@ -122,41 +117,20 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
return result return result
} }
override fun generateArchive(project: Project, context: KobaltContext, zip: Zip, fun generateJar(project: Project, context: KobaltContext, jar: Jar) : File {
includedFiles: List<IncludedFile>) : File { val allFiles = findIncludedFiles(project, context, jar)
// //
// Generate the manifest // Generate the manifest
// If manifest attributes were specified in the build file, use those to generateAndSave the manifest. Otherwise,
// try to find a META-INF/MANIFEST.MF and use that one if we find any. Otherwise, use the default manifest.
// //
val manifest = val manifest = java.util.jar.Manifest()//FileInputStream(mf))
if (zip.attributes.size > 1) { jar.attributes.forEach { attribute ->
context.logger.log(project.name, 2, "Creating MANIFEST.MF from " + zip.attributes.size + " attributes") manifest.mainAttributes.putValue(attribute.first, attribute.second)
Manifest().apply { }
zip.attributes.forEach { attribute -> val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) }
mainAttributes.putValue(attribute.first, attribute.second)
}
}
} else {
fun findManifestFile(project: Project, includedFiles: List<IncludedFile>): File? {
val allFiles = includedFiles.flatMap { file ->
file.allFromFiles(project.directory).map { file.from(it.path) }
}
val manifestFiles = allFiles.filter { it.path.contains(MetaArchive.MANIFEST_MF) }
return if (manifestFiles.any()) manifestFiles[0] else null
}
val manifestFile = findManifestFile(project, includedFiles) return Archives.generateArchive(project, context, jar.name, ".jar", allFiles,
if (manifestFile != null) { true /* expandJarFiles */, jarFactory)
context.logger.log(project.name, 2, "Including MANIFEST.MF file $manifestFile")
Manifest(FileInputStream(manifestFile))
} else {
null
}
}
return Archives.generateArchive(project, context, zip.name, ".jar", includedFiles,
true /* expandJarFiles */, manifest)
} }
} }

View file

@ -2,18 +2,18 @@ package com.beust.kobalt
import java.io.File import java.io.File
abstract class JavaInfo { abstract public class JavaInfo {
val javaExecutable: File? public var javaExecutable: File? = null
get() = findExecutable("java") get() = findExecutable("java")
val javacExecutable: File? public var javacExecutable: File? = null
get() = findExecutable("javac") get() = findExecutable("javac")
val javadocExecutable: File? public var javadocExecutable: File? = null
get() = findExecutable("javadoc") get() = findExecutable("javadoc")
abstract var javaHome: File? abstract public var javaHome: File?
abstract var runtimeJar: File? abstract public var runtimeJar: File?
abstract var toolsJar: File? abstract public var toolsJar: File?
abstract fun findExecutable(command: String) : File abstract public fun findExecutable(command: String) : File
companion object { companion object {
fun create(javaBase: File?): Jvm { fun create(javaBase: File?): Jvm {

View file

@ -1,18 +1,18 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import com.beust.kobalt.misc.warn import com.beust.kobalt.misc.warn
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
open class Jvm constructor( public open class Jvm constructor(
val os: OperatingSystem, val os: OperatingSystem,
var javaBase: File? = null) : JavaInfo() { var javaBase: File? = null) : JavaInfo() {
private var _javaHome: File? = null private var _javaHome: File? = null
override var javaHome: File? = null override public var javaHome: File? = null
get() = _javaHome!! get() = _javaHome!!
override var runtimeJar: File? = null override public var runtimeJar: File? = null
private fun findRuntimeJar() : File? { private fun findRuntimeJar() : File? {
var runtimeJar = File(javaBase, "lib/rt.jar") var runtimeJar = File(javaBase, "lib/rt.jar")
if (runtimeJar.exists()) { if (runtimeJar.exists()) {
@ -21,7 +21,7 @@ open class Jvm constructor(
runtimeJar = File(javaBase, "jre/lib/rt.jar") runtimeJar = File(javaBase, "jre/lib/rt.jar")
return if (runtimeJar.exists()) runtimeJar else null return if (runtimeJar.exists()) runtimeJar else null
} }
override var toolsJar: File? = null override public var toolsJar: File? = null
private var userSupplied: Boolean? = false private var userSupplied: Boolean? = false
private var javaVersion: String? = null private var javaVersion: String? = null
@ -67,7 +67,7 @@ open class Jvm constructor(
return toolsJar return toolsJar
} }
if (javaHome!!.name.equals("jre", true)) { if (javaHome!!.name.equals("jre", true)) {
_javaHome = javaHome!!.parentFile javaHome = javaHome!!.parentFile
toolsJar = File(javaHome, "lib/tools.jar") toolsJar = File(javaHome, "lib/tools.jar")
if (toolsJar.exists()) { if (toolsJar.exists()) {
return toolsJar return toolsJar
@ -78,7 +78,7 @@ open class Jvm constructor(
val version = SystemProperties.Companion.javaVersion val version = SystemProperties.Companion.javaVersion
if (javaHome!!.name.toRegex().matches("jre\\d+") if (javaHome!!.name.toRegex().matches("jre\\d+")
|| javaHome!!.name == "jre$version") { || javaHome!!.name == "jre$version") {
_javaHome = File(javaHome!!.parentFile, "jdk$version") javaHome = File(javaHome!!.parentFile, "jdk$version")
toolsJar = File(javaHome, "lib/tools.jar") toolsJar = File(javaHome, "lib/tools.jar")
if (toolsJar.exists()) { if (toolsJar.exists()) {
return toolsJar return toolsJar
@ -89,15 +89,15 @@ open class Jvm constructor(
return null return null
} }
// open fun isIbmJvm(): Boolean { // open public fun isIbmJvm(): Boolean {
// return false // return false
// } // }
override fun findExecutable(command: String): File { override public fun findExecutable(command: String): File {
if (javaHome != null) { if (javaHome != null) {
val jdkHome = if (javaHome!!.endsWith("jre")) javaHome!!.parentFile else javaHome val jdkHome = if (javaHome!!.endsWith("jre")) javaHome!!.parentFile else javaHome
val exec = File(jdkHome, "bin/" + command) val exec = File(jdkHome, "bin/" + command)
val executable = File(os.getExecutableName(exec.absolutePath)) var executable = File(os.getExecutableName(exec.absolutePath))
if (executable.isFile) { if (executable.isFile) {
return executable return executable
} }
@ -110,7 +110,7 @@ open class Jvm constructor(
val pathExecutable = os.findInPath(command) val pathExecutable = os.findInPath(command)
if (pathExecutable != null) { if (pathExecutable != null) {
kobaltLog(2, "Unable to find the $command executable using home: " + log(2, "Unable to find the $command executable using home: " +
"$javaHome but found it on the PATH: $pathExecutable.") "$javaHome but found it on the PATH: $pathExecutable.")
return pathExecutable return pathExecutable
} }

View file

@ -3,15 +3,14 @@ package com.beust.kobalt
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.IncrementalTask import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.internal.IncrementalManager
import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.misc.JarUtils import com.beust.kobalt.misc.JarUtils
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import com.google.inject.Provider import com.google.inject.Provider
import java.io.File import java.io.File
import java.lang.reflect.Method import java.lang.reflect.Method
@ -26,9 +25,9 @@ import javax.inject.Singleton
class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManager>, class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManager>,
val files: KFiles, val files: KFiles,
val depManager: DependencyManager, val depManager: DependencyManager,
val settings: KobaltSettings, val localRepo: LocalRepo,
val executors: KobaltExecutors, val executors: KobaltExecutors,
val incrementalManagerFactory: IncrementalManager.IFactory, val pluginInfo: PluginInfo,
val taskManager: TaskManager) { val taskManager: TaskManager) {
companion object { companion object {
@ -64,7 +63,7 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManage
} }
// Call apply() on each plug-in that accepts a project // Call apply() on each plug-in that accepts a project
kobaltLog(2, "Applying plug-in \"${plugin.name}\"") log(2, "Applying plug-in \"${plugin.name}\"")
projects.filter { plugin.accept(it) }.forEach { project -> projects.filter { plugin.accept(it) }.forEach { project ->
plugin.apply(project, context) plugin.apply(project, context)
} }
@ -80,26 +79,7 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManage
// Collect all the tasks from the task contributors // Collect all the tasks from the task contributors
context.pluginInfo.taskContributors.forEach { context.pluginInfo.taskContributors.forEach {
projects.forEach { project -> taskManager.dynamicTasks.addAll(it.tasksFor(context))
taskManager.dynamicTasks.addAll(it.tasksFor(project, context))
}
}
// ... and from the incremental task contributors
val incrementalManager = incrementalManagerFactory.create()
context.pluginInfo.incrementalTaskContributors.forEach {
projects.forEach { project ->
it.incrementalTasksFor(project, context).forEach {
// Convert the closure (Project) -> IncrementalTaskInfo to (Project) -> TaskResult
// and create a DynamicTask out of it
val closure =
incrementalManager.toIncrementalTaskClosure(it.name, it.incrementalClosure, Variant())
val task = DynamicTask(it.plugin, it.name, it.doc, it.group, it.project, it.dependsOn,
it.reverseDependsOn, it.runBefore, it.runAfter, it.alwaysRunAfter,
closure)
taskManager.dynamicTasks.add(task)
}
}
} }
// Now that we have collected all static and dynamic tasks, turn them all into plug-in tasks // Now that we have collected all static and dynamic tasks, turn them all into plug-in tasks
@ -170,9 +150,6 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManage
val dependencies = arrayListOf<IClasspathDependency>() val dependencies = arrayListOf<IClasspathDependency>()
// @Inject
// lateinit var pluginInfo: PluginInfo
fun installPlugins(dependencies: List<IClasspathDependency>, scriptClassLoader: ClassLoader) { fun installPlugins(dependencies: List<IClasspathDependency>, scriptClassLoader: ClassLoader) {
val executor = executors.newExecutor("Plugins", 5) val executor = executors.newExecutor("Plugins", 5)
dependencies.forEach { dependencies.forEach {
@ -193,8 +170,6 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider<TaskManage
// The plug-in is pointing to a jar file, read kobalt-plugin.xml from it // The plug-in is pointing to a jar file, read kobalt-plugin.xml from it
JarUtils.extractTextFile(JarFile(file), PluginInfo.PLUGIN_XML) JarUtils.extractTextFile(JarFile(file), PluginInfo.PLUGIN_XML)
} }
val pluginInfo = Kobalt.INJECTOR.getInstance(PluginInfo::class.java)
if (pluginXml != null) { if (pluginXml != null) {
val pluginClassLoader = URLClassLoader(arrayOf(file.toURI().toURL())) val pluginClassLoader = URLClassLoader(arrayOf(file.toURI().toURL()))
val thisPluginInfo = PluginInfo.readPluginXml(pluginXml, pluginClassLoader, scriptClassLoader) val thisPluginInfo = PluginInfo.readPluginXml(pluginXml, pluginClassLoader, scriptClassLoader)

View file

@ -3,11 +3,11 @@ package com.beust.kobalt
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.MavenId import com.beust.kobalt.maven.MavenId
import com.beust.kobalt.maven.aether.* import com.beust.kobalt.maven.aether.KobaltAether
import com.beust.kobalt.misc.* import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.Node
import com.beust.kobalt.misc.log
import com.google.inject.Inject import com.google.inject.Inject
import org.eclipse.aether.artifact.DefaultArtifact
import org.eclipse.aether.graph.DependencyNode
import java.util.* import java.util.*
/** /**
@ -15,7 +15,7 @@ import java.util.*
*/ */
class ResolveDependency @Inject constructor( class ResolveDependency @Inject constructor(
val localRepo: LocalRepo, val localRepo: LocalRepo,
val aether: KobaltMavenResolver, val aether: KobaltAether,
val executors: KobaltExecutors) { val executors: KobaltExecutors) {
val increment = 8 val increment = 8
val leftFirst = "\u2558" val leftFirst = "\u2558"
@ -25,37 +25,13 @@ class ResolveDependency @Inject constructor(
class Dep(val dep: IClasspathDependency, val level: Int) class Dep(val dep: IClasspathDependency, val level: Int)
fun run(id: String) = displayDependenciesFor(id) fun run(ids: List<String>) = ids.forEach { displayDependenciesFor(it) }
private fun latestMavenArtifact(group: String, artifactId: String, extension: String = "jar"): DependencyNode {
val artifact = DefaultArtifact(group, artifactId, extension, "(0,]")
val resolved = aether.resolveRange(artifact)
if (resolved != null) {
val newArtifact = DefaultArtifact(artifact.groupId, artifact.artifactId, artifact.extension,
resolved.highestVersion.toString())
val artifactResult = aether.resolve(KobaltMavenResolver.artifactToId(newArtifact), null)
return artifactResult.root
} else {
throw KobaltException("Couldn't find latest artifact for $group:$artifactId")
}
}
class PairResult(val dependency: IClasspathDependency, val repoUrl: String)
fun latestArtifact(group: String, artifactId: String, extension: String = "jar"): PairResult
= latestMavenArtifact(group, artifactId, extension).let {
PairResult(AetherDependency(it.artifact), "(TBD repo)")
}
private fun displayDependenciesFor(id: String) { private fun displayDependenciesFor(id: String) {
val mavenId = MavenId.create(id) val mavenId = MavenId.create(id)
val resolved : PairResult = val resolved =
if (mavenId.hasVersion) { if (mavenId.hasVersion) aether.resolve(id)
val node = aether.resolve(id, filter = Filters.EXCLUDE_OPTIONAL_FILTER) else aether.latestArtifact(mavenId.groupId, mavenId.artifactId)
PairResult(AetherDependency(node.root.artifact), node.artifactResults[0].repository.toString())
} else {
latestArtifact(mavenId.groupId, mavenId.artifactId)
}
displayDependencies(resolved.dependency, resolved.repoUrl) displayDependencies(resolved.dependency, resolved.repoUrl)
} }
@ -66,10 +42,10 @@ class ResolveDependency @Inject constructor(
val seen = hashSetOf(dep.id) val seen = hashSetOf(dep.id)
root.addChildren(findChildren(root, seen)) root.addChildren(findChildren(root, seen))
kobaltLog(1, AsciiArt.logBox(listOf(dep.id, url, dep.jarFile.get()).map { " $it" })) AsciiArt.logBox(listOf(dep.id, url, dep.jarFile.get()).map { " $it" }, {s -> println(s) })
display(root.children) display(root.children)
kobaltLog(1, "") println("")
} }
private fun display(nodes: List<Node<Dep>>) { private fun display(nodes: List<Node<Dep>>) {
@ -81,12 +57,10 @@ class ResolveDependency @Inject constructor(
else leftMiddle else leftMiddle
val indent = level * increment val indent = level * increment
for(i in 0..indent - 2) { for(i in 0..indent - 2) {
if (!KobaltLogger.isQuiet) { if (i % increment == 0) print(vertical)
if (i == 0 || ((i + 1) % increment == 0)) print(vertical) else print(" ")
else print(" ")
}
} }
kobaltLog(1, left + " " + dep.id + (if (dep.optional) " (optional)" else "")) println(left + " " + dep.id)
display(node.children) display(node.children)
} }
} }
@ -99,18 +73,13 @@ class ResolveDependency @Inject constructor(
if (! seen.contains(it.id)) { if (! seen.contains(it.id)) {
val dep = Dep(it, root.value.level + 1) val dep = Dep(it, root.value.level + 1)
val node = Node(dep) val node = Node(dep)
kobaltLog(2, "Found dependency ${dep.dep.id} level: ${dep.level}") log(2, "Found dependency ${dep.dep.id} level: ${dep.level}")
result.add(node) result.add(node)
seen.add(it.id) seen.add(it.id)
try { node.addChildren(findChildren(node, seen))
node.addChildren(findChildren(node, seen))
} catch(ex: Exception) {
if (! it.optional) warn("Couldn't resolve " + node)
// else don't warn about missing optional dependencies
}
} }
} }
kobaltLog(2, "Children for ${root.value.dep.id}: ${result.size}") log(2, "Children for ${root.value.dep.id}: ${result.size}")
return result return result
} }
} }

View file

@ -1,17 +1,9 @@
package com.beust.kobalt package com.beust.kobalt
class SystemProperties { public class SystemProperties {
companion object { companion object {
val javaBase : String val javaBase = System.getProperty("java.home") ?:
get() { (System.getenv("JAVA_HOME") ?: throw IllegalArgumentException("JAVA_HOME not defined"))
val jh = System.getenv("JAVA_HOME")
?: System.getProperty("java.home")
?: throw IllegalArgumentException("JAVA_HOME not defined")
val result =
if (jh.toLowerCase().endsWith("jre")) jh.substring(0, jh.length - 4)
else jh
return result
}
val javaVersion = System.getProperty("java.version") val javaVersion = System.getProperty("java.version")
val homeDir = System.getProperty("user.home") val homeDir = System.getProperty("user.home")
val tmpDir = System.getProperty("java.io.tmpdir") val tmpDir = System.getProperty("java.io.tmpdir")

View file

@ -1,8 +1,3 @@
package com.beust.kobalt package com.beust.kobalt
class TestResult(val success: Boolean, val shortMessage: String? = null, val longMessage: String? = null) open public class TaskResult(val success: Boolean = true, val errorMessage: String? = null)
open class TaskResult(val success: Boolean = true,
val testResult: TestResult? = null,
val errorMessage: String? = null
)

View file

@ -1,40 +0,0 @@
package com.beust.kobalt
import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.Directive
class TestConfig(val project: Project, val isDefault : Boolean = false) {
val testArgs = arrayListOf<String>()
val jvmArgs = arrayListOf<String>()
val testIncludes = arrayListOf("**/*Test.class")
val testExcludes = arrayListOf<String>()
@Directive
var name: String = ""
@Directive
fun args(vararg arg: String) {
testArgs.addAll(arg)
}
@Directive
fun jvmArgs(vararg arg: String) {
jvmArgs.addAll(arg)
}
@Directive
fun include(vararg arg: String) {
testIncludes.apply {
clear()
addAll(arg)
}
}
@Directive
fun exclude(vararg arg: String) {
testExcludes.apply {
clear()
addAll(arg)
}
}
}

View file

@ -3,13 +3,43 @@ package com.beust.kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
class TestConfig(val project: Project) {
val testArgs = arrayListOf<String>()
val jvmArgs = arrayListOf<String>()
val testIncludes = arrayListOf("**/*.class")
val testExcludes = arrayListOf<String>()
var name: String = ""
fun args(vararg arg: String) {
testArgs.addAll(arg)
}
fun jvmArgs(vararg arg: String) {
jvmArgs.addAll(arg)
}
fun includes(vararg arg: String) {
testIncludes.apply {
clear()
addAll(arg)
}
}
fun excludes(vararg arg: String) {
testExcludes.apply {
clear()
addAll(arg)
}
}
}
@Directive @Directive
fun Project.test(init: TestConfig.() -> Unit): TestConfig = let { project -> fun Project.test(init: TestConfig.() -> Unit) = let { project ->
with(testConfigs) { with(testConfigs) {
val tf = TestConfig(project).apply { init() } val tf = TestConfig(project).apply { init() }
if (! map { it.name }.contains(tf.name)) { if (! map { it.name }.contains(tf.name)) {
add(tf) add(tf)
tf
} else { } else {
throw KobaltException("Test configuration \"${tf.name}\" already exists, give it a different " throw KobaltException("Test configuration \"${tf.name}\" already exists, give it a different "
+ "name with test { name = ... }") + "name with test { name = ... }")

View file

@ -2,9 +2,9 @@ package com.beust.kobalt
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.internal.ActorUtils import com.beust.kobalt.internal.ActorUtils
import com.beust.kobalt.internal.ParallelLogger
import com.beust.kobalt.internal.SourceSet import com.beust.kobalt.internal.SourceSet
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -29,7 +29,7 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
/** /**
* for {internal, release}, return [internalRelease, internal, release] * for {internal, release}, return [internalRelease, internal, release]
*/ */
fun allDirectories(): List<String> { fun allDirectories(project: Project): List<String> {
return arrayListOf<String>().apply { return arrayListOf<String>().apply {
add(toCamelcaseDir()) add(toCamelcaseDir())
add(productFlavor.name) add(productFlavor.name)
@ -70,27 +70,28 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
val result = arrayListOf<File>() val result = arrayListOf<File>()
val sourceDirectories = sourceSet.correctSourceSet(project) val sourceDirectories = sourceSet.correctSourceSet(project)
.filter { File(project.directory, it).exists() } .filter { File(project.directory, it).exists() }
.map(::File) .map { File(it) }
if (isDefault) { if (isDefault) {
result.addAll(sourceDirectories) result.addAll(sourceDirectories)
} else { } else {
// // The ordering of files is: 1) build type 2) product flavor 3) default // // The ordering of files is: 1) build type 2) product flavor 3) default
val kobaltLog = Kobalt.INJECTOR.getInstance(ParallelLogger::class.java)
buildType.let { buildType.let {
val dir = File(KFiles.joinDir("src", it.name, suffix)) val dir = File(KFiles.joinDir("src", it.name, suffix))
kobaltLog.log(project.name, 3, "Adding source for build type ${it.name}: ${dir.path}") log(3, "Adding source for build type ${it.name}: ${dir.path}")
result.add(dir) result.add(dir)
} }
productFlavor.let { productFlavor.let {
val dir = File(KFiles.joinDir("src", it.name, suffix)) val dir = File(KFiles.joinDir("src", it.name, suffix))
kobaltLog.log(project.name, 3, "Adding source for product flavor ${it.name}: ${dir.path}") log(3, "Adding source for product flavor ${it.name}: ${dir.path}")
result.add(dir) result.add(dir)
} }
result.addAll(allDirectories() result.addAll(allDirectories(project).map {
.map { File(KFiles.joinDir("src", it, suffix)) } File(KFiles.joinDir("src", it, suffix))
.filter(File::exists)) }.filter {
it.exists()
})
// Now that all the variant source directories have been added, add the project's default ones // Now that all the variant source directories have been added, add the project's default ones
result.addAll(sourceDirectories) result.addAll(sourceDirectories)
@ -113,8 +114,8 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
if (isDefault) { if (isDefault) {
archiveName ?: project.name + "-" + project.version + suffix archiveName ?: project.name + "-" + project.version + suffix
} else { } else {
val base = archiveName?.substring(0, archiveName.length - suffix.length) val base = if (archiveName != null) archiveName.substring(0, archiveName.length - suffix.length)
?: project.name + "-" + project.version else project.name + "-" + project.version
val flavor = if (productFlavor.name.isEmpty()) "" else "-" + productFlavor.name val flavor = if (productFlavor.name.isEmpty()) "" else "-" + productFlavor.name
val type = if (buildType.name.isEmpty()) "" else "-" + buildType.name val type = if (buildType.name.isEmpty()) "" else "-" + buildType.name
val result: String = base + flavor + type + suffix val result: String = base + flavor + type + suffix
@ -124,16 +125,18 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
return result return result
} }
val shortArchiveName = if (isDefault) "" else "-" + productFlavor.name + "-" + buildType.name
var generatedSourceDirectory: File? = null var generatedSourceDirectory: File? = null
private fun findBuildTypeBuildConfig(project: Project, variant: Variant?) : BuildConfig? { private fun findBuildTypeBuildConfig(project: Project, variant: Variant?) : BuildConfig? {
val buildTypeName = variant?.buildType?.name val buildTypeName = variant?.buildType?.name
return project.buildTypes[buildTypeName]?.buildConfig return project.buildTypes[buildTypeName]?.buildConfig ?: null
} }
private fun findProductFlavorBuildConfig(project: Project, variant: Variant?) : BuildConfig? { private fun findProductFlavorBuildConfig(project: Project, variant: Variant?) : BuildConfig? {
val buildTypeName = variant?.productFlavor?.name val buildTypeName = variant?.productFlavor?.name
return project.productFlavors[buildTypeName]?.buildConfig return project.productFlavors[buildTypeName]?.buildConfig ?: null
} }
/** /**
@ -151,7 +154,7 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
/** /**
* Generate BuildConfig.java if requested. Also look up if any BuildConfig is defined on the current build type, * 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 * product flavor or main project, and use them to generate any additional field (in that order to
* respect the priorities). Return the generated file if it was generated, null otherwise. * respect the priorities). Return the generated file if it was generated, null otherwise.
*/ */
fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) : File? { fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) : File? {
@ -160,10 +163,9 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
if (buildConfigs.size > 0) { if (buildConfigs.size > 0) {
val pkg = project.packageName ?: project.group val pkg = project.packageName ?: project.group
?: throw KobaltException( ?: throw KobaltException(
"packageName needs to be defined on the project in order to generateAndSave BuildConfig") "packageName needs to be defined on the project in order to generate BuildConfig")
val contributor = ActorUtils.selectAffinityActor(project, context, val contributor = ActorUtils.selectAffinityActor(context.pluginInfo.buildConfigContributors, project)
context.pluginInfo.buildConfigContributors)
if (contributor != null) { if (contributor != null) {
val code = contributor.generateBuildConfig(project, context, pkg, this, buildConfigs) val code = contributor.generateBuildConfig(project, context, pkg, this, buildConfigs)
val result = KFiles.makeDir(KFiles.generatedSourceDir(project, this, "buildConfig")) val result = KFiles.makeDir(KFiles.generatedSourceDir(project, this, "buildConfig"))
@ -173,10 +175,10 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar)) val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar))
val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig." + contributor.buildConfigSuffix) val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig." + contributor.buildConfigSuffix)
KFiles.saveFile(outputDir, code) KFiles.saveFile(outputDir, code)
context.logger.log(project.name, 2, "Generated ${outputDir.path}") log(2, "Generated ${outputDir.path}")
return result return result
} else { } else {
throw KobaltException("Couldn't find a contributor to generateAndSave BuildConfig") throw KobaltException("Couldn't find a contributor to generate BuildConfig")
} }
} else { } else {
return null return null
@ -221,7 +223,7 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
} }
fun toCamelcaseDir() : String { fun toCamelcaseDir() : String {
fun lci(s : String) = if (s.isEmpty() || s.length == 1) s else s[0].toLowerCase() + s.substring(1) fun lci(s : String) = if (s.length == 0 || s.length == 1) s else s[0].toLowerCase() + s.substring(1)
return lci(productFlavor.name) + buildType.name.capitalize() return lci(productFlavor.name) + buildType.name.capitalize()
} }

View file

@ -10,7 +10,6 @@ data class CompilerActionInfo(val directory: String?,
val sourceFiles: List<String>, val sourceFiles: List<String>,
val suffixesBeingCompiled: List<String>, val suffixesBeingCompiled: List<String>,
val outputDir: File, val outputDir: File,
val compilerArgs: List<String>, val compilerArgs: List<String>)
val friendPaths: List<String>,
val forceRecompile: Boolean,
val compilerSeparateProcess: Boolean = false)

View file

@ -11,12 +11,9 @@ interface IDependencyHolder {
var project: Project var project: Project
val compileDependencies : ArrayList<IClasspathDependency> val compileDependencies : ArrayList<IClasspathDependency>
val optionalDependencies : ArrayList<IClasspathDependency>
val compileProvidedDependencies : ArrayList<IClasspathDependency> val compileProvidedDependencies : ArrayList<IClasspathDependency>
val compileOnlyDependencies : ArrayList<IClasspathDependency>
val compileRuntimeDependencies : ArrayList<IClasspathDependency> val compileRuntimeDependencies : ArrayList<IClasspathDependency>
val excludedDependencies : ArrayList<IClasspathDependency> val excludedDependencies : ArrayList<IClasspathDependency>
val nativeDependencies : ArrayList<IClasspathDependency>
@Directive @Directive
var dependencies: Dependencies? var dependencies: Dependencies?
@ -28,18 +25,15 @@ interface IDependencyHolder {
open class DependencyHolder : IDependencyHolder { open class DependencyHolder : IDependencyHolder {
override lateinit var project: Project override lateinit var project: Project
override val compileDependencies : ArrayList<IClasspathDependency> = arrayListOf() override val compileDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val optionalDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val compileProvidedDependencies : ArrayList<IClasspathDependency> = arrayListOf() override val compileProvidedDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val compileOnlyDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val compileRuntimeDependencies : ArrayList<IClasspathDependency> = arrayListOf() override val compileRuntimeDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val excludedDependencies : ArrayList<IClasspathDependency> = arrayListOf() override val excludedDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override val nativeDependencies : ArrayList<IClasspathDependency> = arrayListOf()
override var dependencies : Dependencies? = null override var dependencies : Dependencies? = null
override fun dependencies(init: Dependencies.() -> Unit) : Dependencies { override fun dependencies(init: Dependencies.() -> Unit) : Dependencies {
dependencies = Dependencies(project, compileDependencies, optionalDependencies, compileProvidedDependencies, dependencies = Dependencies(project, compileDependencies, compileProvidedDependencies,
compileOnlyDependencies, compileRuntimeDependencies, excludedDependencies, nativeDependencies) compileRuntimeDependencies, excludedDependencies)
dependencies!!.init() dependencies!!.init()
return dependencies!! return dependencies!!
} }

View file

@ -5,7 +5,7 @@ import com.beust.kobalt.Variant
/** /**
* Plug-ins that can generate a BuildConfig file. * Plug-ins that can generate a BuildConfig file.
*/ */
interface IBuildConfigContributor : IProjectAffinity { interface IBuildConfigContributor : ISimpleAffinity<Project> {
fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant, fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant,
buildConfigs: List<BuildConfig>) : String buildConfigs: List<BuildConfig>) : String

View file

@ -1,20 +0,0 @@
package com.beust.kobalt.api
/**
* Plug-ins that listen to build events.
*/
interface IBuildListener : IListener {
class TaskEndInfo(val success: Boolean, val shortMessage: String? = null,
val longMessage: String? = null)
fun taskStart(project: Project, context: KobaltContext, taskName: String) {}
fun taskEnd(project: Project, context: KobaltContext, taskName: String, info: TaskEndInfo) {}
fun projectStart(project: Project, context: KobaltContext) {}
fun projectEnd(project: Project, context: KobaltContext, status: ProjectBuildStatus) {}
}
enum class ProjectBuildStatus {
SUCCESS, FAILED, SKIPPED
}

View file

@ -1,8 +0,0 @@
package com.beust.kobalt.api
/**
* Plug-ins that produce build reports.
*/
interface IBuildReportContributor : IContributor {
fun generateReport(context: KobaltContext)
}

View file

@ -22,20 +22,15 @@ interface IClasspathDependency {
/** @return true if this dependency represents a Maven coordinate */ /** @return true if this dependency represents a Maven coordinate */
val isMaven: Boolean val isMaven: Boolean
/** @return true if this dependency is optional */
val optional: Boolean
/** Absolute path to the jar file on the local file system */ /** Absolute path to the jar file on the local file system */
val jarFile: Future<File> val jarFile: Future<File>
/** Convert to a Maven <dependency> model tag */ /** Convert to a Maven <dependency> model tag */
fun toMavenDependencies(scope: String? = null) : Dependency fun toMavenDependencies() : Dependency
/** The list of dependencies for this element (not the transitive closure) */ /** The list of dependencies for this element (not the transitive closure) */
fun directDependencies(): List<IClasspathDependency> fun directDependencies(): List<IClasspathDependency>
/** Used to only keep the most recent version for an artifact if no version was specified */ /** Used to only keep the most recent version for an artifact if no version was specified */
val shortId: String val shortId: String
val excluded: ArrayList<Dependencies.ExcludeConfig>
} }

View file

@ -2,12 +2,7 @@ package com.beust.kobalt.api
import com.beust.kobalt.TaskResult import com.beust.kobalt.TaskResult
interface ICompilerDescription : Comparable<ICompilerDescription> { interface ICompiler : Comparable<ICompiler> {
/**
* The name of the language compiled by this compiler.
*/
val name: String
/** /**
* The suffixes handled by this compiler (without the dot, e.g. "java" or "kt"). * The suffixes handled by this compiler (without the dot, e.g. "java" or "kt").
*/ */
@ -32,7 +27,7 @@ interface ICompilerDescription : Comparable<ICompilerDescription> {
*/ */
val priority: Int get() = DEFAULT_PRIORITY val priority: Int get() = DEFAULT_PRIORITY
override fun compareTo(other: ICompilerDescription) = priority.compareTo(other.priority) override fun compareTo(other: ICompiler) = priority.compareTo(other.priority)
/** /**
* Can this compiler be passed directories or does it need individual source files? * Can this compiler be passed directories or does it need individual source files?
@ -41,28 +36,5 @@ interface ICompilerDescription : Comparable<ICompilerDescription> {
} }
interface ICompilerContributor : IProjectAffinity, IContributor { interface ICompilerContributor : IProjectAffinity, IContributor {
fun compilersFor(project: Project, context: KobaltContext): List<ICompilerDescription> fun compilersFor(project: Project, context: KobaltContext): List<ICompiler>
} }
interface ICompiler {
fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo): TaskResult
}
class CompilerDescription(override val name: String, override val sourceDirectory: String,
override val sourceSuffixes: List<String>, val compiler: ICompiler,
override val priority: Int = ICompilerDescription.DEFAULT_PRIORITY,
override val canCompileDirectories: Boolean = false) : ICompilerDescription {
override fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo): TaskResult {
val result =
if (info.sourceFiles.isNotEmpty()) {
compiler.compile(project, context, info)
} else {
context.logger.log(project.name, 2, "$name couldn't find any source files to compile")
TaskResult()
}
return result
}
override fun toString() = name + " compiler"
}

View file

@ -3,27 +3,13 @@ package com.beust.kobalt.api
/** /**
* Plugins that add compiler flags. * Plugins that add compiler flags.
*/ */
class FlagContributor(val flagPriority: Int = DEFAULT_FLAG_PRIORITY, interface ICompilerFlagContributor : IContributor {
val closure: (project: Project, context: KobaltContext, currentFlags: List<String>, fun flagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>) -> List<String>) : IContributor { suffixesBeingCompiled: List<String>): List<String>
val flagPriority: Int
get() = DEFAULT_FLAG_PRIORITY
companion object { companion object {
val DEFAULT_FLAG_PRIORITY = 20 val DEFAULT_FLAG_PRIORITY = 20
} }
fun flagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>) = closure(project, context, currentFlags, suffixesBeingCompiled)
} }
interface IFlagBase {
val flagPriority: Int get() = FlagContributor.DEFAULT_FLAG_PRIORITY
}
interface ICompilerFlagContributor : IContributor, IFlagBase {
fun compilerFlagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>): List<String>
}
interface IDocFlagContributor : IContributor, IFlagBase {
fun docFlagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>): List<String>
}

View file

@ -1,12 +1,5 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.maven.aether.Filters.EXCLUDE_OPTIONAL_FILTER
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.misc.kobaltLog
import org.eclipse.aether.graph.DependencyFilter
import org.eclipse.aether.graph.DependencyNode
/** /**
* Manage the creation of dependencies and also provide dependencies for projects. * Manage the creation of dependencies and also provide dependencies for projects.
*/ */
@ -14,12 +7,12 @@ interface IDependencyManager {
/** /**
* Parse the id and return the correct IClasspathDependency * Parse the id and return the correct IClasspathDependency
*/ */
fun create(id: String, optional: Boolean = false, projectDirectory: String? = null): IClasspathDependency fun create(id: String, projectDirectory: String? = null): IClasspathDependency
/** /**
* Create an IClasspathDependency from a Maven id. * Create an IClasspathDependency from a Maven id.
*/ */
fun createMaven(id: String, optional: Boolean = false): IClasspathDependency fun createMaven(id: String): IClasspathDependency
/** /**
* Create an IClasspathDependency from a path. * Create an IClasspathDependency from a path.
@ -29,7 +22,7 @@ interface IDependencyManager {
/** /**
* @return the source dependencies for this project, including the contributors. * @return the source dependencies for this project, including the contributors.
*/ */
fun dependencies(project: Project, context: KobaltContext, scopes: List<Scope>): List<IClasspathDependency> fun dependencies(project: Project, context: KobaltContext): List<IClasspathDependency>
/** /**
* @return the test dependencies for this project, including the contributors. * @return the test dependencies for this project, including the contributors.
@ -41,48 +34,5 @@ interface IDependencyManager {
* allDependencies is typically either compileDependencies or testDependencies * allDependencies is typically either compileDependencies or testDependencies
*/ */
fun calculateDependencies(project: Project?, context: KobaltContext, fun calculateDependencies(project: Project?, context: KobaltContext,
dependencyFilter: DependencyFilter = vararg allDependencies: List<IClasspathDependency>): List<IClasspathDependency>
createDependencyFilter(project, project?.compileDependencies ?: emptyList()),
scopes: List<Scope> = listOf(Scope.COMPILE),
vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency>
/**
* Create an Aether dependency filter that uses the dependency configuration included in each
* IClasspathDependency.
*/
fun createDependencyFilter(project: Project?, dependencies: List<IClasspathDependency>) : DependencyFilter {
return DependencyFilter { p0, p1 ->
fun isNodeExcluded(node: DependencyNode, passedDep: IClasspathDependency) : Boolean {
val dep = create(KobaltMavenResolver.artifactToId(node.artifact))
return passedDep.excluded.any { ex -> ex.isExcluded(dep)}
}
fun isDepExcluded(node: DependencyNode, excluded: List<IClasspathDependency>?) : Boolean {
val dep = create(KobaltMavenResolver.artifactToId(node.artifact))
return excluded?.map { it.id }?.contains(dep.id) ?: false
}
val accept = dependencies.isEmpty() || dependencies.any {
// Is this dependency excluded?
val isExcluded = isNodeExcluded(p0, it) || isDepExcluded(p0, project?.excludedDependencies)
// Is the parent dependency excluded?
val isParentExcluded =
if (p1.any()) {
isNodeExcluded(p1[0], it) || isDepExcluded(p1[0], project?.excludedDependencies)
} else {
false
}
// Only accept if no exclusions were found
! isExcluded && ! isParentExcluded
}
if (! accept) {
kobaltLog(2, "Excluding $p0")
}
if (accept) EXCLUDE_OPTIONAL_FILTER.accept(p0, p1)
else accept
}
}
} }

View file

@ -1,28 +0,0 @@
package com.beust.kobalt.api
import com.beust.kobalt.IncrementalTaskInfo
/**
* Plug-ins that need to add incremental dynamic tasks (tasks that are not methods annotated with @Task) need
* to implement this interface.
*/
interface IIncrementalTaskContributor : IContributor {
fun incrementalTasksFor(project: Project, context: KobaltContext) : List<IncrementalDynamicTask>
}
class IncrementalDynamicTask(val context: KobaltContext,
val plugin: IPlugin,
val name: String,
val doc: String,
val group: String,
val project: Project,
val dependsOn: List<String> = listOf<String>(),
val reverseDependsOn: List<String> = listOf<String>(),
val runBefore: List<String> = listOf<String>(),
val runAfter: List<String> = listOf<String>(),
val alwaysRunAfter: List<String> = listOf<String>(),
val incrementalClosure: (Project) -> IncrementalTaskInfo) {
override fun toString() = "[IncrementalDynamicTask $name dependsOn=$dependsOn reverseDependsOn=$reverseDependsOn]"
}

View file

@ -1,13 +0,0 @@
package com.beust.kobalt.api
/**
* Plug-ins that add flags to the JVM used to run apps should implement this interface.
*/
interface IJvmFlagContributor : IContributor {
/**
* The list of JVM flags that will be added to the JVM when the app gets run. @param[currentFlags] is only here
* for convenience, in case you need to look at the current JVM flags before adding your own flags.
*/
fun jvmFlagsFor(project: Project, context: KobaltContext, currentFlags: List<String>) : List<String>
}

View file

@ -1,8 +0,0 @@
package com.beust.kobalt.api
/**
* Plug-ins that want to override the local maven repo path.
*/
interface ILocalMavenRepoPathInterceptor : IInterceptor {
fun repoPath(currentPath: String) : String
}

View file

@ -10,6 +10,3 @@ interface IPluginActor {
interface IContributor : IPluginActor interface IContributor : IPluginActor
interface IInterceptor : IPluginActor interface IInterceptor : IPluginActor
interface IListener : IPluginActor

View file

@ -1,11 +1,10 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.TaskResult import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.IClasspathDependency
/** /**
* Plugins that can run a project (task "run" or "test") should implement this interface. * Plugins that can run a project (task "run" or "test") should implement this interface.
*
* Currently not used.
*/ */
interface IRunnerContributor : IContributor, IProjectAffinity { interface IRunnerContributor : IContributor, IProjectAffinity {
/** /**

View file

@ -8,5 +8,5 @@ interface ISimpleAffinity<T> : IAffinity {
* @return an integer indicating the affinity of your actor. The actor that returns * @return an integer indicating the affinity of your actor. The actor that returns
* the highest affinity gets selected. * the highest affinity gets selected.
*/ */
fun affinity(project: T) : Int fun affinity(arg: T) : Int
} }

View file

@ -8,7 +8,7 @@ import com.beust.kobalt.internal.TaskResult2
* to implement this interface. * to implement this interface.
*/ */
interface ITaskContributor : IContributor { interface ITaskContributor : IContributor {
fun tasksFor(project: Project, context: KobaltContext) : List<DynamicTask> fun tasksFor(context: KobaltContext) : List<DynamicTask>
} }
class DynamicTask(override val plugin: IPlugin, override val name: String, override val doc: String, class DynamicTask(override val plugin: IPlugin, override val name: String, override val doc: String,
@ -23,10 +23,9 @@ class DynamicTask(override val plugin: IPlugin, override val name: String, overr
override fun call(): TaskResult2<ITask> { override fun call(): TaskResult2<ITask> {
val taskResult = closure.invoke(project) val taskResult = closure.invoke(project)
return TaskResult2(taskResult.success, errorMessage = taskResult.errorMessage, value = this) return TaskResult2(taskResult.success, taskResult.errorMessage, this)
} }
override fun toString() = override fun toString() = "[DynamicTask $name dependsOn=$dependsOn reverseDependsOn=$reverseDependsOn]"
"[DynamicTask ${project.name}:$name dependsOn=$dependsOn reverseDependsOn=$reverseDependsOn]"
} }

View file

@ -1,55 +0,0 @@
package com.beust.kobalt.api
import com.beust.kobalt.Args
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import java.io.*
import java.net.URL
import java.util.jar.JarInputStream
/**
* Base class for templates that decompress a jar file.
*/
interface InputStreamJarTemplate : ITemplate {
val inputStream: InputStream
override fun generateTemplate(args: Args, classLoader: ClassLoader) {
val destDir = File(".")
JarInputStream(inputStream).use { ins ->
var entry = ins.nextEntry
while (entry != null) {
val f = File(destDir.path + File.separator + entry.name)
if (entry.isDirectory) {
f.mkdir()
entry = ins.nextEntry
continue
}
kobaltLog(2, " Extracting: $entry to ${f.absolutePath}")
FileOutputStream(f).use { fos ->
KFiles.copy(ins, fos)
}
entry = ins.nextEntry
}
}
}
}
abstract class ResourceJarTemplate(jarName: String, val classLoader: ClassLoader) : InputStreamJarTemplate {
override val inputStream : InputStream = classLoader.getResource(jarName).openConnection().inputStream
}
abstract class FileJarTemplate(val fileName: String) : InputStreamJarTemplate {
override val inputStream = FileInputStream(File(fileName))
}
abstract class HttpJarTemplate(val url: String) : InputStreamJarTemplate {
override val inputStream : InputStream
get() {
try {
return URL(url).openConnection().inputStream
} catch(ex: IOException) {
throw IllegalArgumentException("Couldn't connect to $url")
}
}
}

View file

@ -0,0 +1,41 @@
package com.beust.kobalt.api
import com.beust.kobalt.Args
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
import java.io.File
import java.io.FileOutputStream
import java.util.jar.JarInputStream
/**
* Base class for templates that simply decompress a jar file to generate their project.
*/
abstract class JarTemplate(val jarName: String) : ITemplate {
companion object {
fun extractFile(ins: JarInputStream, destDir: File) {
var entry = ins.nextEntry
while (entry != null) {
val f = File(destDir.path + File.separator + entry.name)
if (entry.isDirectory) {
f.mkdir()
entry = ins.nextEntry
continue
}
log(2, "Extracting: $entry to ${f.absolutePath}")
FileOutputStream(f).use { fos ->
KFiles.copy(ins, fos)
}
entry = ins.nextEntry
}
}
}
override fun generateTemplate(args: Args, classLoader: ClassLoader) {
log(2, "Generating template with class loader $classLoader")
val destDir = File(".")
val ins = JarInputStream(classLoader.getResource(jarName).openConnection().inputStream)
extractFile(ins, destDir)
}
}

View file

@ -4,8 +4,6 @@ import com.beust.kobalt.Constants
import com.beust.kobalt.HostConfig import com.beust.kobalt.HostConfig
import com.beust.kobalt.Plugins import com.beust.kobalt.Plugins
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.google.inject.Guice import com.google.inject.Guice
import com.google.inject.Injector import com.google.inject.Injector
import com.google.inject.Module import com.google.inject.Module
@ -32,16 +30,18 @@ class Kobalt {
var context: KobaltContext? = null var context: KobaltContext? = null
/** /**
* @return the repos calculated from various places where repos can be specified. * @return the repos calculated from the following places:
* - Either repos specified in settings.xml or from Constants.DEFAULT_REPOS
* - Repos from the build file
*/ */
val repos : Set<HostConfig> val repos : Set<HostConfig>
get() { get() {
val settingsRepos = Kobalt.context?.settings?.defaultRepos?.map { HostConfig(it) } ?: emptyList() val settingsRepos = Kobalt.context?.settings?.defaultRepos ?: emptyList()
// Repos from <default-repos> in the settings // Repos from <default-repos> in the settings
val result = ArrayList( val result = ArrayList(
(if (settingsRepos.isEmpty()) Constants.DEFAULT_REPOS (if (settingsRepos.isEmpty()) Constants.DEFAULT_REPOS
else settingsRepos) else settingsRepos)
) .map { HostConfig(it) })
// Repo from <kobalt-compiler-repo> in the settings // Repo from <kobalt-compiler-repo> in the settings
Kobalt.context?.settings?.kobaltCompilerRepo?.let { Kobalt.context?.settings?.kobaltCompilerRepo?.let {
@ -56,9 +56,6 @@ class Kobalt {
// Repos from the build file // Repos from the build file
result.addAll(reposFromBuildFiles) result.addAll(reposFromBuildFiles)
result.forEach {
KobaltMavenResolver.initAuthentication(it)
}
return result.toHashSet() return result.toHashSet()
} }
@ -68,13 +65,6 @@ class Kobalt {
if (repo.url.endsWith("/")) repo if (repo.url.endsWith("/")) repo
else repo.copy(url = (repo.url + "/"))) else repo.copy(url = (repo.url + "/")))
val buildFileClasspath = arrayListOf<IClasspathDependency>()
fun addBuildFileClasspath(dep: String) {
val dependencyManager = Kobalt.INJECTOR.getInstance(DependencyManager::class.java)
buildFileClasspath.add(dependencyManager.create(dep))
}
private val KOBALT_PROPERTIES = "kobalt.properties" private val KOBALT_PROPERTIES = "kobalt.properties"
private val PROPERTY_KOBALT_VERSION = "kobalt.version" private val PROPERTY_KOBALT_VERSION = "kobalt.version"
private val PROPERTY_KOBALT_VERSION_CHECK_TIMEOUT = "kobalt.version.checkTimeout" // ISO-8601 private val PROPERTY_KOBALT_VERSION_CHECK_TIMEOUT = "kobalt.version.checkTimeout" // ISO-8601
@ -122,20 +112,5 @@ class Kobalt {
get() = Duration.parse( kobaltProperties.getProperty(PROPERTY_KOBALT_VERSION_CHECK_TIMEOUT) ?: "P1D") get() = Duration.parse( kobaltProperties.getProperty(PROPERTY_KOBALT_VERSION_CHECK_TIMEOUT) ?: "P1D")
fun findPlugin(name: String) = Plugins.findPlugin(name) fun findPlugin(name: String) = Plugins.findPlugin(name)
val optionsFromBuild = arrayListOf<String>()
fun addKobaltOptions(options: Array<out String>) {
optionsFromBuild.addAll(options)
}
val buildSourceDirs = arrayListOf<String>()
fun addBuildSourceDirs(dirs: Array<out String>) {
buildSourceDirs.addAll(dirs)
}
fun cleanUp() {
buildSourceDirs.clear()
buildFileClasspath.clear()
}
} }
} }

View file

@ -1,18 +1,11 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins import com.beust.kobalt.Plugins
import com.beust.kobalt.Variant import com.beust.kobalt.Variant
import com.beust.kobalt.internal.ILogger
import com.beust.kobalt.internal.IncrementalManager
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.MavenId
import com.beust.kobalt.maven.PomGenerator
import com.beust.kobalt.maven.SimpleDep
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
import java.io.File import java.io.File
@ -21,54 +14,13 @@ class KobaltContext(val args: Args) {
val profiles = arrayListOf<String>() val profiles = arrayListOf<String>()
init { init {
args.profiles?.split(',')?.filterNotNull()?.forEach { args.profiles?.split(",")?.filterNotNull()?.forEach {
profiles.add(it) profiles.add(it)
} }
} }
fun findPlugin(name: String) = Plugins.findPlugin(name) fun findPlugin(name: String) = Plugins.findPlugin(name)
/**
* Files that can be resolved in the local cache.
*/
enum class FileType { JAR, POM, SOURCES, JAVADOC, OTHER }
/**
* @param{id} is the Maven coordinate (e.g. "org.testng:testng:6.9.11"). If you are looking for a file
* that is not described by the enum (e.g. "aar"), use OTHER and make sure your @param{id} contains
* the fully qualified id (e.g. "com.example:example::aar:1.0").
*/
fun fileFor(id: String, fileType: FileType) : File {
val dep = SimpleDep(MavenId.create(id))
fun toQualifier(dep: SimpleDep, ext: String, qualifier: String?) =
dep.groupId + ":" + dep.artifactId +
":$ext" +
(if (qualifier != null) ":$qualifier" else "") +
":" + dep.version
val fullId =
when (fileType) {
FileType.JAR -> toQualifier(dep, "jar", null)
FileType.POM -> toQualifier(dep, "pom", null)
FileType.SOURCES -> toQualifier(dep, "", "sources")
FileType.JAVADOC -> toQualifier(dep, "", "javadoc")
FileType.OTHER -> id
}
val resolved = resolver.resolveToArtifact(fullId)
if (resolved != null) {
return resolved.file
} else {
throw KobaltException("Couldn't resolve $id")
}
}
/**
* @return the content of the pom.xml for the given project.
*/
fun generatePom(project: Project) = pomGeneratorFactory.create(project).generate()
/** All the projects that are being built during this run */
val allProjects = arrayListOf<Project>()
/** For internal use only */ /** For internal use only */
val internalContext = InternalContext() val internalContext = InternalContext()
@ -80,10 +32,6 @@ class KobaltContext(val args: Args) {
lateinit var dependencyManager: DependencyManager lateinit var dependencyManager: DependencyManager
lateinit var executors: KobaltExecutors lateinit var executors: KobaltExecutors
lateinit var settings: KobaltSettings lateinit var settings: KobaltSettings
lateinit var incrementalManager: IncrementalManager
lateinit var resolver: KobaltMavenResolver
lateinit var pomGeneratorFactory: PomGenerator.IFactory
lateinit var logger: ILogger
} }
class InternalContext { class InternalContext {
@ -105,12 +53,4 @@ class InternalContext {
* The absolute directory of the current project. * The absolute directory of the current project.
*/ */
var absoluteDir: File? = null var absoluteDir: File? = null
/**
* If true, will force a recompile of the files even if using the incremental compile
*/
var forceRecompile: Boolean = false
var noIncrementalKotlin: Boolean = false
} }

View file

@ -2,17 +2,13 @@ package com.beust.kobalt.api
import com.beust.kobalt.TestConfig import com.beust.kobalt.TestConfig
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.AetherDependency
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import org.apache.maven.model.Model
import java.io.File import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.Future import java.util.concurrent.Future
import java.util.concurrent.FutureTask import java.util.concurrent.FutureTask
import java.util.regex.Pattern
open class Project( open class Project(
@Directive open var name: String = "", @Directive open var name: String = "",
@ -23,10 +19,9 @@ open class Project(
@Directive open var artifactId: String? = null, @Directive open var artifactId: String? = null,
@Directive open var packaging: String? = null, @Directive open var packaging: String? = null,
@Directive open var description : String = "", @Directive open var description : String = "",
@Directive open var scm : Scm? = null,
@Directive open var url: String? = null, @Directive open var url: String? = null,
@Directive open var pom: Model? = null, @Directive open var licenses: List<License> = arrayListOf<License>(),
@Directive open var dependsOn: ArrayList<Project> = arrayListOf<Project>(),
@Directive open var testsDependOn: ArrayList<Project> = arrayListOf<Project>(),
@Directive open var packageName: String? = group) @Directive open var packageName: String? = group)
: IBuildConfig, IDependencyHolder by DependencyHolder() { : IBuildConfig, IDependencyHolder by DependencyHolder() {
@ -34,15 +29,15 @@ open class Project(
this.project = this this.project = this
} }
fun allProjectDependedOn() = project.dependsOn + project.testsDependOn
class ProjectExtra(project: Project) { class ProjectExtra(project: Project) {
val dependsOn = arrayListOf<Project>()
var isDirty = false var isDirty = false
/** /**
* @return true if any of the projects we depend on is dirty. * @return true if any of the projects we depend on is dirty.
*/ */
fun dependsOnDirtyProjects(project: Project) = project.allProjectDependedOn().any { it.projectExtra.isDirty } fun dependsOnDirtyProjects(project: Project) = project.projectExtra.dependsOn.any { it.projectExtra.isDirty }
} }
/** /**
@ -53,7 +48,7 @@ open class Project(
val testConfigs = arrayListOf<TestConfig>() val testConfigs = arrayListOf<TestConfig>()
// If one is specified by default, we only generateAndSave a BuildConfig, find a way to fix that // If one is specified by default, we only generate a BuildConfig, find a way to fix that
override var buildConfig : BuildConfig? = null // BuildConfig() override var buildConfig : BuildConfig? = null // BuildConfig()
val projectProperties = ProjectProperties() val projectProperties = ProjectProperties()
@ -61,6 +56,10 @@ open class Project(
override fun equals(other: Any?) = name == (other as Project).name override fun equals(other: Any?) = name == (other as Project).name
override fun hashCode() = name.hashCode() override fun hashCode() = name.hashCode()
/** Can be used by plug-ins */
val dependentProjects : List<ProjectDescription>
get() = projectProperties.get(JvmCompilerPlugin.DEPENDENT_PROJECTS) as List<ProjectDescription>
companion object { companion object {
val DEFAULT_SOURCE_DIRECTORIES = setOf("src/main/java", "src/main/kotlin", "src/main/resources") val DEFAULT_SOURCE_DIRECTORIES = setOf("src/main/java", "src/main/kotlin", "src/main/resources")
val DEFAULT_SOURCE_DIRECTORIES_TEST = setOf("src/test/java", "src/test/kotlin", "src/test/resources") val DEFAULT_SOURCE_DIRECTORIES_TEST = setOf("src/test/java", "src/test/kotlin", "src/test/resources")
@ -90,9 +89,8 @@ open class Project(
@Directive @Directive
fun dependenciesTest(init: Dependencies.() -> Unit) : Dependencies { fun dependenciesTest(init: Dependencies.() -> Unit) : Dependencies {
dependencies = Dependencies(this, testDependencies, arrayListOf(), dependencies = Dependencies(this, testDependencies, testProvidedDependencies, compileRuntimeDependencies,
testProvidedDependencies, compileOnlyDependencies, compileRuntimeDependencies, excludedDependencies)
excludedDependencies, nativeDependencies)
dependencies!!.init() dependencies!!.init()
return dependencies!! return dependencies!!
} }
@ -100,9 +98,6 @@ open class Project(
val testDependencies : ArrayList<IClasspathDependency> = arrayListOf() val testDependencies : ArrayList<IClasspathDependency> = arrayListOf()
val testProvidedDependencies : ArrayList<IClasspathDependency> = arrayListOf() val testProvidedDependencies : ArrayList<IClasspathDependency> = arrayListOf()
fun testsDependOn(vararg projects: Project) = testsDependOn.addAll(projects)
fun dependsOn(vararg projects: Project) = dependsOn.addAll(projects)
/** Used to disambiguate various name properties */ /** Used to disambiguate various name properties */
@Directive @Directive
val projectName: String get() = name val projectName: String get() = name
@ -128,20 +123,6 @@ open class Project(
}) })
return result return result
} }
class Dep(val file: File, val id: String)
/**
* @return a list of the transitive dependencies (absolute paths to jar files) for the given dependencies.
* Can be used for example as `collect(compileDependencies)`.
*/
@Directive
fun collect(dependencies: List<IClasspathDependency>) : List<Dep> {
return (Kobalt.context?.dependencyManager?.transitiveClosure(dependencies) ?: emptyList())
.map { Dep(it.jarFile.get(), it.id) }
}
override fun toString() = "[Project $name]"
} }
class Sources(val project: Project, val sources: HashSet<String>) { class Sources(val project: Project, val sources: HashSet<String>) {
@ -153,12 +134,9 @@ class Sources(val project: Project, val sources: HashSet<String>) {
class Dependencies(val project: Project, class Dependencies(val project: Project,
val dependencies: ArrayList<IClasspathDependency>, val dependencies: ArrayList<IClasspathDependency>,
val optionalDependencies: ArrayList<IClasspathDependency>,
val providedDependencies: ArrayList<IClasspathDependency>, val providedDependencies: ArrayList<IClasspathDependency>,
val compileOnlyDependencies: ArrayList<IClasspathDependency>,
val runtimeDependencies: ArrayList<IClasspathDependency>, val runtimeDependencies: ArrayList<IClasspathDependency>,
val excludedDependencies: ArrayList<IClasspathDependency>, val excludedDependencies: ArrayList<IClasspathDependency>) {
val nativeDependencies: ArrayList<IClasspathDependency>) {
/** /**
* Add the dependencies to the given ArrayList and return a list of future jar files corresponding to * Add the dependencies to the given ArrayList and return a list of future jar files corresponding to
@ -167,107 +145,35 @@ class Dependencies(val project: Project,
* future tasks receive a get(), the repos will be correct. * future tasks receive a get(), the repos will be correct.
*/ */
private fun addToDependencies(project: Project, dependencies: ArrayList<IClasspathDependency>, private fun addToDependencies(project: Project, dependencies: ArrayList<IClasspathDependency>,
dep: Array<out String>, optional: Boolean = false, excludeConfig: ExcludeConfig? = null): List<Future<File>> dep: Array<out String>): List<Future<File>>
= with(dep.map { = with(dep.map { DependencyManager.create(it, project.directory)}) {
val resolved =
if (KobaltMavenResolver.isRangeVersion(it)) {
// Range id
val node = Kobalt.INJECTOR.getInstance(KobaltMavenResolver::class.java).resolveToArtifact(it)
val result = KobaltMavenResolver.artifactToId(node)
kobaltLog(2, "Resolved range id $it to $result")
result
} else {
it
}
DependencyManager.create(resolved, optional, project.directory)
}) {
dependencies.addAll(this) dependencies.addAll(this)
if (excludeConfig != null) {
this.forEach { it.excluded.add(excludeConfig) }
}
this.map { FutureTask { it.jarFile.get() } } this.map { FutureTask { it.jarFile.get() } }
} }
@Directive @Directive
fun compile(vararg dep: String) = addToDependencies(project, dependencies, dep) fun compile(vararg dep: String) = addToDependencies(project, dependencies, dep)
class ExcludeConfig {
val ids = arrayListOf<String>()
@Directive
fun exclude(vararg passedIds: String) = ids.addAll(passedIds)
class ArtifactConfig(
var groupId: String? = null,
var artifactId: String? = null,
var version: String? = null
)
val artifacts = arrayListOf<ArtifactConfig>()
@Directive
fun exclude(groupId: String? = null, artifactId: String? = null, version: String? = null)
= artifacts.add(ArtifactConfig(groupId, artifactId, version))
fun match(pattern: String?, id: String) : Boolean {
return pattern == null || Pattern.compile(pattern).matcher(id).matches()
}
/**
* @return true if the dependency is excluded with any of the exclude() directives. The matches
* are performed by a regular expression match against the dependency.
*/
fun isExcluded(dep: IClasspathDependency) : Boolean {
// Straight id match
var result = ids.any { match(it, dep.id) }
// Match on any combination of (groupId, artifactId, version)
if (! result && dep.isMaven) {
val mavenDep = dep as AetherDependency
val artifact = mavenDep.artifact
result = artifacts.any {
val match1 = it.groupId == null || match(it.groupId, artifact.groupId)
val match2 = it.artifactId == null || match(it.artifactId, artifact.artifactId)
val match3 = it.version == null || match(it.version, artifact.version)
match1 && match2 && match3
}
}
return result
}
}
@Directive @Directive
fun compile(dep: String, init: ExcludeConfig.() -> Unit) { fun provided(vararg dep: String) = addToDependencies(project, providedDependencies, dep)
val excludeConfig = ExcludeConfig().apply {
init()
}
addToDependencies(project, dependencies, arrayOf(dep), excludeConfig = excludeConfig)
}
@Directive
fun compileOnly(vararg dep: String) = addToDependencies(project, compileOnlyDependencies, dep)
@Directive
fun compileOptional(vararg dep: String) {
addToDependencies(project, optionalDependencies, dep, optional = true)
addToDependencies(project, dependencies, dep, optional = true)
}
@Directive
fun provided(vararg dep: String) {
addToDependencies(project, providedDependencies, dep)
}
@Directive @Directive
fun runtime(vararg dep: String) = addToDependencies(project, runtimeDependencies, dep) fun runtime(vararg dep: String) = addToDependencies(project, runtimeDependencies, dep)
@Directive @Directive
fun exclude(vararg dep: String) = addToDependencies(project, excludedDependencies, dep) fun exclude(vararg dep: String) = addToDependencies(project, excludedDependencies, dep)
}
class Scm(val connection: String, val developerConnection: String, val url: String)
class License(val name: String, val url: String) {
fun toMavenLicense() : org.apache.maven.model.License {
val result = org.apache.maven.model.License()
result.name = name
result.url = url
return result
}
@Directive
fun native(vararg dep: String) = addToDependencies(project, nativeDependencies, dep)
} }
class BuildConfig { class BuildConfig {

View file

@ -44,25 +44,6 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
} }
} }
fun addTask(plugin: IPlugin, project: Project, taskName: String, description: String,
group: String = AnnotationDefault.GROUP,
dependsOn: List<String> = emptyList(),
reverseDependsOn : List<String> = emptyList(),
runBefore : List<String> = emptyList(),
runAfter : List<String> = emptyList(),
alwaysRunAfter: List<String> = emptyList(),
runTask: (Project) -> TaskResult) {
dynamicTasks.add(DynamicTask(plugin, taskName, description, group, project,
dependsOn = dependsOn,
reverseDependsOn = reverseDependsOn,
runBefore = runBefore,
runAfter = runAfter,
alwaysRunAfter = alwaysRunAfter,
closure = { p: Project ->
runTask(project)
}))
}
fun addIncrementalVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String, fun addIncrementalVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String,
group: String = AnnotationDefault.GROUP, group: String = AnnotationDefault.GROUP,
dependsOn: List<String> = emptyList(), dependsOn: List<String> = emptyList(),
@ -72,7 +53,6 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
runTask: (Project) -> IncrementalTaskInfo) { runTask: (Project) -> IncrementalTaskInfo) {
Variant.allVariants(project).forEach { variant -> Variant.allVariants(project).forEach { variant ->
val variantTaskName = variant.toTask(taskName) val variantTaskName = variant.toTask(taskName)
context.variant = variant
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName, group, project, dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName, group, project,
dependsOn = dependsOn.map { variant.toTask(it) }, dependsOn = dependsOn.map { variant.toTask(it) },
reverseDependsOn = reverseDependsOn.map { variant.toTask(it) }, reverseDependsOn = reverseDependsOn.map { variant.toTask(it) },
@ -82,5 +62,5 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
} }
} }
override fun tasksFor(project: Project, context: KobaltContext) : List<DynamicTask> = dynamicTasks override fun tasksFor(context: KobaltContext) : List<DynamicTask> = dynamicTasks
} }

View file

@ -1,24 +1,25 @@
package com.beust.kobalt.archive package com.beust.kobalt.archive
import com.beust.kobalt.* import com.beust.kobalt.Features
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.ExportedProjectProperty import com.beust.kobalt.api.annotation.ExportedProjectProperty
import com.beust.kobalt.misc.IncludedFile
import com.beust.kobalt.misc.JarUtils import com.beust.kobalt.misc.JarUtils
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import java.util.* import java.util.*
import java.util.zip.ZipOutputStream
class Archives { class Archives {
companion object { companion object {
@ExportedProjectProperty(doc = "The name of the jar file", type = "String") @ExportedProjectProperty(doc = "The name of the jar file", type = "String")
const val JAR_NAME = "jarName" const val JAR_NAME = "jarName"
@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 + private val DEFAULT_STREAM_FACTORY = { os : OutputStream -> ZipOutputStream(os) }
if (project.version.isNullOrBlank()) "" else "-${project.version}"
fun generateArchive(project: Project, fun generateArchive(project: Project,
context: KobaltContext, context: KobaltContext,
@ -26,29 +27,24 @@ class Archives {
suffix: String, suffix: String,
includedFiles: List<IncludedFile>, includedFiles: List<IncludedFile>,
expandJarFiles : Boolean = false, expandJarFiles : Boolean = false,
manifest: java.util.jar.Manifest? = null) : File { outputStreamFactory: (OutputStream) -> ZipOutputStream = DEFAULT_STREAM_FACTORY) : File {
val fullArchiveName = context.variant.archiveName(project, archiveName, suffix) val fullArchiveName = context.variant.archiveName(project, archiveName, suffix)
val archiveDir = File(KFiles.libsDir(project)) val archiveDir = File(KFiles.libsDir(project))
val result = File(archiveDir.path, fullArchiveName) val result = File(archiveDir.path, fullArchiveName)
context.logger.log(project.name, 3, "Creating $result") log(3, "Creating $result")
if (! Features.USE_TIMESTAMPS || isOutdated(project.directory, includedFiles, result)) { if (! Features.USE_TIMESTAMPS || isOutdated(project.directory, includedFiles, result)) {
try { val outStream = outputStreamFactory(FileOutputStream(result))
MetaArchive(result, manifest).use { metaArchive -> JarUtils.addFiles(project.directory, includedFiles, outStream, expandJarFiles)
JarUtils.addFiles(project.directory, includedFiles, metaArchive, expandJarFiles) log(2, text = "Added ${includedFiles.size} files to $result")
context.logger.log(project.name, 2, "Added ${includedFiles.size} files to $result") outStream.flush()
context.logger.log(project.name, 1, " Created $result") outStream.close()
} log(1, " Created $result")
} catch (e: Throwable) {
// make sure that incomplete archive is deleted
// otherwise incremental build does not work on next run
result.delete()
throw e
}
} else { } else {
context.logger.log(project.name, 3, " $result is up to date") log(3, " $result is up to date")
} }
project.projectProperties.put(JAR_NAME, result.absolutePath)
return result return result
} }
@ -59,21 +55,13 @@ class Archives {
includedFiles.forEach { root -> includedFiles.forEach { root ->
val allFiles = root.allFromFiles(directory) val allFiles = root.allFromFiles(directory)
allFiles.forEach { relFile -> allFiles.forEach { relFile ->
val file = if (relFile.isAbsolute) val file = File(KFiles.joinDir(directory, root.from, relFile.path))
relFile // e.g. jar file or classes folder (of another project) when building a fat jar
else
File(KFiles.joinDir(directory, root.from, relFile.path))
if (file.isFile) { if (file.isFile) {
if (file.lastModified() > lastModified) { if (file.lastModified() > lastModified) {
kobaltLog(3, " TS - Outdated $file and $output " log(3, " TS - Outdated $file and $output "
+ Date(file.lastModified()) + " " + Date(output.lastModified())) + Date(file.lastModified()) + " " + Date(output.lastModified()))
return true return true
} }
} else if (file.isDirectory) {
// e.g. classes folder (of another project) when building a fat jar
val includedFile = IncludedFile(From(""), To(""), listOf(IFileSpec.GlobSpec("**")))
if (isOutdated(file.absolutePath, listOf(includedFile), output))
return true
} }
} }
} }

View file

@ -1,14 +1,11 @@
package com.beust.kobalt.archive package com.beust.kobalt.archive
import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
/** /**
* A jar is exactly like a zip with the addition of a manifest and an optional fatJar boolean. * A jar is exactly like a zip with the addition of a manifest and an optional fatJar boolean.
*/ */
open class Jar(override val project: Project, open class Jar(override var name: String? = null, var fatJar: Boolean = false) : Zip(name), AttributeHolder {
override var name : String = Archives.defaultArchiveName(project) + ".jar",
override var fatJar: Boolean = false) : Zip(project, name, fatJar), AttributeHolder {
@Directive @Directive
fun manifest(init: Manifest.(p: Manifest) -> Unit) : Manifest { fun manifest(init: Manifest.(p: Manifest) -> Unit) : Manifest {
val m = Manifest(this) val m = Manifest(this)
@ -18,7 +15,7 @@ open class Jar(override val project: Project,
// Need to specify the version or attributes will just be dropped // Need to specify the version or attributes will just be dropped
@Directive @Directive
override val attributes = arrayListOf(Pair("Manifest-Version", "1.0")) val attributes = arrayListOf(Pair("Manifest-Version", "1.0"))
override fun addAttribute(k: String, v: String) { override fun addAttribute(k: String, v: String) {
attributes.add(Pair(k, v)) attributes.add(Pair(k, v))

View file

@ -1,125 +0,0 @@
package com.beust.kobalt.archive
import com.beust.kobalt.Glob
import com.beust.kobalt.misc.KFiles
import org.apache.commons.compress.archivers.ArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
import java.io.Closeable
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.jar.Manifest
import org.apache.commons.compress.archivers.zip.ZipFile as ApacheZipFile
/**
* Abstraction of a zip/jar/war archive that automatically manages the addition of expanded jar files.
* Uses ZipArchiveOutputStream for fast inclusion of expanded jar files.
*/
class MetaArchive(outputFile: File, val manifest: Manifest?) : Closeable {
companion object {
const val MANIFEST_MF = "META-INF/MANIFEST.MF"
}
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)
}
}
}
}
private val createdDirs = hashSetOf<String>()
/**
* 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<String>()
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
for (entry in jarEntries) {
maybeAddEntry(entry) {
zos.addRawArchiveEntry(entry, jar.getRawInputStream(entry))
}
}
}
}
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
}
override fun close() = zos.close()
private fun addEntry(entry: ArchiveEntry, inputStream: FileInputStream?) {
zos.putArchiveEntry(entry)
inputStream?.use { ins ->
ins.copyTo(zos, 50 * 1024)
}
zos.closeArchiveEntry()
}
private val seen = hashSetOf<String>()
private fun maybeAddEntry(entry: ArchiveEntry, action:() -> Unit) {
entry.name.let { name ->
if (!seen.contains(name) && okToAdd(name)) {
action()
}
seen.add(name)
}
}
}

View file

@ -1,12 +1,10 @@
package com.beust.kobalt.archive package com.beust.kobalt.archive
import com.beust.kobalt.api.Project
import com.beust.kobalt.glob import com.beust.kobalt.glob
class War(override val project: Project, override var name: String = Archives.defaultArchiveName(project) + ".war") class War(override var name: String? = null) : Jar(name), AttributeHolder {
: Jar(project, name), AttributeHolder {
init { init {
include(from("src/main/webapp"), to(""), glob("**")) include(from("src/main/webapp"),to(""), glob("**"))
include(from("kobaltBuild/classes"), to("WEB-INF/classes"), glob("**")) include(from("kobaltBuild/classes"), to("WEB-INF/classes"), glob("**"))
} }
} }

View file

@ -1,13 +1,21 @@
package com.beust.kobalt.archive package com.beust.kobalt.archive
import com.beust.kobalt.* import com.beust.kobalt.Glob
import com.beust.kobalt.api.Project import com.beust.kobalt.IFileSpec
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.misc.From
import com.beust.kobalt.misc.IncludedFile
import com.beust.kobalt.misc.To
open class Zip(open val project: Project, open var name: String = Archives.defaultArchiveName(project) + ".zip", open class Zip(open var name: String? = null) {
open var fatJar: Boolean = false): AttributeHolder, IncludeFromTo() {
val excludes = arrayListOf<Glob>() val excludes = arrayListOf<Glob>()
@Directive
fun from(s: String) = From(s)
@Directive
fun to(s: String) = To(s)
@Directive @Directive
fun exclude(vararg files: String) { fun exclude(vararg files: String) {
files.forEach { excludes.add(Glob(it)) } files.forEach { excludes.add(Glob(it)) }
@ -19,9 +27,26 @@ open class Zip(open val project: Project, open var name: String = Archives.defau
} }
@Directive @Directive
open val attributes = arrayListOf(Pair("Manifest-Version", "1.0")) fun include(vararg files: String) {
includedFiles.add(IncludedFile(files.map { IFileSpec.FileSpec(it) }))
override fun addAttribute(k: String, v: String) {
attributes.add(Pair(k, v))
} }
@Directive
fun include(from: From, to: To, vararg specs: String) {
includedFiles.add(IncludedFile(from, to, specs.map { IFileSpec.FileSpec(it) }))
}
@Directive
fun include(from: From, to: To, vararg specs: IFileSpec.GlobSpec) {
includedFiles.add(IncludedFile(from, to, listOf(*specs)))
}
/**
* Prefix path to be removed from the zip file. For example, if you add "build/lib/a.jar" to the zip
* file and the excludePrefix is "build/lib", then "a.jar" will be added at the root of the zip file.
*/
val includedFiles = arrayListOf<IncludedFile>()
} }

View file

@ -1,6 +1,7 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.api.IProjectAffinity import com.beust.kobalt.api.IProjectAffinity
import com.beust.kobalt.api.ISimpleAffinity
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
@ -10,13 +11,19 @@ class ActorUtils {
* Return the plug-in actor with the highest affinity. * Return the plug-in actor with the highest affinity.
*/ */
fun <T : IProjectAffinity> selectAffinityActor(project: Project, context: KobaltContext, actors: List<T>) fun <T : IProjectAffinity> selectAffinityActor(project: Project, context: KobaltContext, actors: List<T>)
= actors.maxBy { it.affinity(project, context) } = actors.maxBy { it.affinity(project, context) }
/** /**
* Return all the plug-in actors with a non zero affinity sorted from the highest to the lowest. * Return all the plug-in actors with a non zero affinity sorted from the highest to the lowest.
*/ */
fun <T : IProjectAffinity> selectAffinityActors(project: Project, context: KobaltContext, actors: List<T>) fun <T : IProjectAffinity> selectAffinityActors(project: Project, context: KobaltContext, actors: List<T>)
= actors.filter { it.affinity(project, context) > 0 } = actors.filter { it.affinity(project, context) > 0 }
.sortedByDescending { it.affinity(project, context) } .sortedByDescending { it.affinity(project, context) }
/**
* Return the plug-in actor with the highest affinity.
*/
fun <T : ISimpleAffinity<A>, A> selectAffinityActor(actors: List<T>, arg: A) = actors.maxBy { it.affinity(arg) }
} }
} }

View file

@ -1,7 +1,9 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.api.* import com.beust.kobalt.api.BasePlugin
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.api.ConfigActor
import com.beust.kobalt.api.ICompilerFlagContributor
import com.beust.kobalt.api.IConfigActor
/** /**
* Base class for JVM language plug-ins. * Base class for JVM language plug-ins.
@ -12,7 +14,7 @@ abstract class BaseJvmPlugin<T>(open val configActor: ConfigActor<T>) :
ICompilerFlagContributor { ICompilerFlagContributor {
companion object { companion object {
// Run before other flag contributors // Run before other flag contributors
val FLAG_CONTRIBUTOR_PRIORITY = FlagContributor.DEFAULT_FLAG_PRIORITY - 10 val FLAG_CONTRIBUTOR_PRIORITY = ICompilerFlagContributor.DEFAULT_FLAG_PRIORITY - 10
} }
protected fun maybeCompilerArgs(sourceSuffixes: List<String>, suffixesBeingCompiled: List<String>, protected fun maybeCompilerArgs(sourceSuffixes: List<String>, suffixesBeingCompiled: List<String>,
@ -21,17 +23,4 @@ abstract class BaseJvmPlugin<T>(open val configActor: ConfigActor<T>) :
override val flagPriority = FLAG_CONTRIBUTOR_PRIORITY override val flagPriority = FLAG_CONTRIBUTOR_PRIORITY
override fun accept(project: Project) = sourceFileCount(project) > 0
// IBuildConfigContributor
protected fun sourceFileCount(project: Project)
= KFiles.findSourceFiles(project.directory, project.sourceDirectories, sourceSuffixes()).size +
KFiles.findSourceFiles(project.directory, project.sourceDirectoriesTest, sourceSuffixes()).size
fun affinity(project: Project) = sourceFileCount(project)
// IDocContributor
open fun affinity(project: Project, context: KobaltContext) = sourceFileCount(project)
abstract fun sourceSuffixes() : List<String>
} }

View file

@ -1,186 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.TestResult
import com.beust.kobalt.api.IBuildListener
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.api.ProjectBuildStatus
import com.beust.kobalt.misc.kobaltLog
import com.google.common.annotations.VisibleForTesting
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import java.util.*
abstract class BaseProjectRunner {
abstract fun runProjects(taskInfos: List<TaskManager.TaskInfo>, projects: List<Project>)
: TaskManager.RunTargetResult
companion object {
val TAG = "graph"
fun runBuildListenersForProject(project: Project, context: KobaltContext, start: Boolean,
status: ProjectBuildStatus = ProjectBuildStatus.SUCCESS) {
context.pluginInfo.buildListeners.forEach {
if (start) it.projectStart(project, context) else it.projectEnd(project, context, status)
}
}
fun runBuildListenersForTask(project: Project, context: KobaltContext, taskName: String, start: Boolean,
success: Boolean = false, testResult: TestResult? = null) {
context.pluginInfo.buildListeners.forEach {
if (start) {
it.taskStart(project, context, taskName)
} else {
val info = IBuildListener.TaskEndInfo(success, testResult?.shortMessage, testResult?.longMessage)
it.taskEnd(project, context, taskName, info)
}
}
}
/**
* Create a graph representing the tasks and their dependencies. That graph will then be run
* in topological order.
*
* @taskNames is the list of tasks requested by the user. @nodeMap maps these tasks to the nodes
* we'll be adding to the graph while @toName extracts the name of a node.
*/
@VisibleForTesting
fun <T> createTaskGraph(projectName: String, passedTasks: List<TaskManager.TaskInfo>,
nodeMap: Multimap<String, T>,
dependsOn: Multimap<String, String>,
reverseDependsOn: Multimap<String, String>,
runBefore: Multimap<String, String>,
runAfter: Multimap<String, String>,
alwaysRunAfter: Multimap<String, String>,
toName: (T) -> String,
accept: (T) -> Boolean):
DynamicGraph<T> {
/**
* Add an edge from @param from to all its tasks.
*/
fun addEdge(result: DynamicGraph<T>, from: String, to: String, newToProcess: ArrayList<T>, text: String) {
val froms = nodeMap[from]
froms.forEach { f: T ->
nodeMap[to].forEach { t: T ->
kobaltLog(TAG, " Adding edge ($text) $f -> $t")
result.addEdge(f, t)
newToProcess.add(t)
}
}
}
val result = DynamicGraph<T>()
val newToProcess = arrayListOf<T>()
val seen = hashSetOf<String>()
//
// Reverse the always map so that tasks can be looked up.
//
val always = ArrayListMultimap.create<String, String>().apply {
alwaysRunAfter.keySet().forEach { k ->
alwaysRunAfter[k].forEach { v ->
put(v, k)
}
}
}
//
// Keep only the tasks we need to run.
//
val taskInfos = passedTasks.filter {
it.matches(projectName)
}
// The nodes we need to process, initialized with the set of tasks requested by the user.
// As we run the graph and discover dependencies, new nodes get added to @param[newToProcess]. At
// the end of the loop, @param[toProcess] is cleared and all the new nodes get added to it. Then we loop.
val toProcess = ArrayList(taskInfos)
while (toProcess.size > 0) {
/**
* Whenever a task is added to the graph, we also add its alwaysRunAfter tasks.
*/
fun processAlways(always: Multimap<String, String>, node: T) {
kobaltLog(TAG, " Processing always for $node")
always[toName(node)]?.let { to: Collection<String> ->
to.forEach { t ->
nodeMap[t].forEach { from ->
kobaltLog(TAG, " Adding always edge $from -> $node")
result.addEdge(from, node)
}
}
kobaltLog(TAG, " ... done processing always for $node")
}
}
kobaltLog(TAG, " Current batch to process: $toProcess")
//
// Move dependsOn + reverseDependsOn in one multimap called allDepends
//
val allDependsOn = ArrayListMultimap.create<String, String>()
dependsOn.keySet().forEach { key ->
dependsOn[key].forEach { value ->
allDependsOn.put(key, value)
}
}
reverseDependsOn.keySet().forEach { key ->
reverseDependsOn[key].forEach { value ->
allDependsOn.put(value, key)
}
}
//
// Process each node one by one
//
toProcess.forEach { taskInfo ->
val taskName = taskInfo.taskName
kobaltLog(TAG, " ***** Current node: $taskName")
nodeMap[taskName].forEach {
result.addNode(it)
processAlways(always, it)
}
//
// dependsOn and reverseDependsOn are considered for all tasks, explicit and implicit
//
allDependsOn[taskName].forEach { to ->
addEdge(result, taskName, to, newToProcess, "dependsOn")
}
seen.add(taskName)
}
newToProcess.forEach { processAlways(always, it) }
toProcess.clear()
toProcess.addAll(
newToProcess
.filter { !seen.contains(toName(it)) }
.map { TaskManager.TaskInfo(toName(it)) })
newToProcess.clear()
}
//
// Now that we have all the tasks tnat need to run, process runBefore/runAfter, which
// are not allowed to add new tasks. Therefore, we only add edges to the graph if both
// the from and the to are already present.
//
val finalTaskNames = result.nodes.map { TaskManager.TaskInfo(it.toString()).taskName }
finalTaskNames.forEach { taskName ->
runBefore[taskName].filter { finalTaskNames.contains(it) }.forEach { from ->
addEdge(result, from, taskName, newToProcess, "runBefore")
}
runAfter[taskName].filter { finalTaskNames.contains(it) }.forEach { to ->
addEdge(result, to, taskName, newToProcess, "runAfter")
}
}
return result
}
}
}

View file

@ -1,128 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.Args
import com.beust.kobalt.AsciiArt
import com.beust.kobalt.api.*
import com.beust.kobalt.misc.kobaltLog
import java.util.concurrent.ConcurrentHashMap
/**
* Record timings and statuses for tasks and projects and display them at the end of the build.
*/
class BuildListeners : IBuildListener, IBuildReportContributor {
class ProfilerInfo(val taskName: String, val durationMillis: Long)
class ProjectInfo(val projectName: String, var durationMillis: Long = 0,
var shortMessage: String? = null, var longMessage: String? = null)
private val startTimes = ConcurrentHashMap<String, Long>()
private val timings = arrayListOf<ProfilerInfo>()
private val projectInfos = hashMapOf<String, ProjectInfo>()
private var hasFailures = false
private val args: Args get() = Kobalt.INJECTOR.getInstance(Args::class.java)
private var buildStartTime: Long? = null
// IBuildListener
override fun taskStart(project: Project, context: KobaltContext, taskName: String) {
startTimes.put(taskName, System.currentTimeMillis())
if (! projectInfos.containsKey(project.name)) {
projectInfos.put(project.name, ProjectInfo(project.name))
}
}
// IBuildListener
override fun taskEnd(project: Project, context: KobaltContext, taskName: String, info: IBuildListener.TaskEndInfo) {
val success = info.success
if (! success) hasFailures = true
startTimes[taskName]?.let {
val taskTime = System.currentTimeMillis() - it
timings.add(ProfilerInfo(taskName, taskTime))
projectInfos[project.name]?.let {
it.durationMillis += taskTime
if (info.shortMessage != null && it.shortMessage == null) it.shortMessage = info.shortMessage
if (info.longMessage != null && it.longMessage == null) it.longMessage = info.longMessage
}
}
}
private val projectStatuses = arrayListOf<Pair<Project, String>>()
// IBuildListener
override fun projectStart(project: Project, context: KobaltContext) {
if (buildStartTime == null) buildStartTime = System.currentTimeMillis()
}
// IBuildListener
override fun projectEnd(project: Project, context: KobaltContext, status: ProjectBuildStatus) {
val shortMessage = projectInfos[project.name]?.shortMessage
val statusText = status.toString() + (if (shortMessage != null) " ($shortMessage)" else "")
projectStatuses.add(Pair(project, statusText))
}
// IBuildReportContributor
override fun generateReport(context: KobaltContext) {
fun formatMillis(millis: Long, format: String) = String.format(format, millis.toDouble() / 1000)
fun formatMillisRight(millis: Long, length: Int) = formatMillis(millis, "%1\$$length.2f")
fun formatMillisLeft(millis: Long, length: Int) = formatMillis(millis, "%1\$-$length.2f")
fun millisToSeconds(millis: Long) = (millis.toDouble() / 1000).toInt()
val profiling = args.profiling
if (profiling) {
kobaltLog(1, "\n" + AsciiArt.horizontalSingleLine + " Timings (in seconds)")
timings.sortedByDescending { it.durationMillis }.forEach {
kobaltLog(1, formatMillisRight(it.durationMillis, 10) + " " + it.taskName)
}
kobaltLog(1, "\n")
}
// Calculate the longest short message so we can create a column long enough to contain it
val width = 12 + (projectInfos.values.map { it.shortMessage?.length ?: 0 }.maxBy { it } ?: 0)
fun col1(s: String) = String.format(" %1\$-30s", s)
fun col2(s: String) = String.format(" %1\$-${width}s", s)
fun col3(s: String) = String.format(" %1\$-8s", s)
// Only print the build report if there is more than one project and at least one of them failed
if (timings.any()) {
// if (timings.size > 1 && hasFailures) {
val line = listOf(col1("Project"), col2("Build status"), col3("Time"))
.joinToString(AsciiArt.verticalBar)
val table = StringBuffer()
table.append(AsciiArt.logBox(listOf(line), AsciiArt.bottomLeft2, AsciiArt.bottomRight2, indent = 10) + "\n")
projectStatuses.forEach { pair ->
val projectName = pair.first.name
val cl = listOf(col1(projectName), col2(pair.second),
col3(formatMillisLeft(projectInfos[projectName]!!.durationMillis, 8)))
.joinToString(AsciiArt.verticalBar)
table.append(" " + AsciiArt.verticalBar + " " + cl + " " + AsciiArt.verticalBar + "\n")
}
table.append(" " + AsciiArt.lowerBox(line.length))
kobaltLog(1, table.toString())
// }
}
val buildTime =
if (buildStartTime != null)
millisToSeconds(System.currentTimeMillis() - buildStartTime!!)
else
0
// BUILD SUCCESSFUL / FAILED message
val message =
if (hasFailures) {
String.format("BUILD FAILED", buildTime)
} else if (! args.sequential) {
val sequentialBuildTime = ((projectInfos.values.sumByDouble { it.durationMillis.toDouble() }) / 1000)
.toInt()
String.format("PARALLEL BUILD SUCCESSFUL (%d SECONDS), sequential build would have taken %d seconds",
buildTime, sequentialBuildTime)
} else {
String.format("BUILD SUCCESSFUL (%d SECONDS)", buildTime)
}
kobaltLog(1, message)
}
}

View file

@ -1,14 +0,0 @@
package com.beust.kobalt.internal
fun <T> Collection<T>.doWhile(condition: (T) -> Boolean, action: (T) -> Unit) {
var i = 0
var done = false
while (i < size && ! done) {
elementAt(i).let { element ->
if (! condition(element)) done = true
else action(element)
}
i++
}
}

View file

@ -1,232 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.*
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles
import com.google.inject.Inject
import java.io.File
import java.nio.file.Paths
import java.util.*
/**
* Central place to compile files, used by plug-ins and non plug-ins.
*/
class CompilerUtils @Inject constructor(val files: KFiles, val dependencyManager: DependencyManager) {
class CompilerResult(val successResults: List<TaskResult>, val failedResult: TaskResult?)
fun invokeCompiler(project: Project, context: KobaltContext, compiler: ICompilerDescription,
sourceDirectories: List<File>, isTest: Boolean, buildDirectory: File): CompilerResult {
val results = arrayListOf<TaskResult>()
var failedResult: TaskResult? = null
val contributedSourceDirs =
if (isTest) {
context.testSourceDirectories(project)
} else {
context.sourceDirectories(project)
}
val sourceFiles = KFiles.findSourceFiles(project.directory,
contributedSourceDirs.map { it.path }, compiler.sourceSuffixes)
if (sourceFiles.isNotEmpty()) {
// TODO: createCompilerActionInfo recalculates the source files, only compute them
// once and pass them
val info = createCompilerActionInfo(project, context, compiler, isTest,
sourceDirectories, sourceSuffixes = compiler.sourceSuffixes, buildDirectory = buildDirectory)
val thisResult = invokeCompiler(project, context, compiler, info)
results.addAll(thisResult.successResults)
if (failedResult == null) {
failedResult = thisResult.failedResult
}
} else {
context.logger.log(project.name, 2,
"${compiler.name} compiler not running on ${project.name} since no source files were found")
}
return CompilerResult(results, failedResult)
}
fun invokeCompiler(project: Project, context: KobaltContext, compiler: ICompilerDescription, info: CompilerActionInfo)
: CompilerResult {
val results = arrayListOf<TaskResult>()
var failedResult: TaskResult? = null
val thisResult = compiler.compile(project, context, info)
results.add(thisResult)
if (!thisResult.success && failedResult == null) {
failedResult = thisResult
}
return CompilerResult(results, failedResult)
}
/**
* Create a CompilerActionInfo (all the information that a compiler needs to know) for the given parameters.
* Runs all the contributors and interceptors relevant to that task.
*/
fun createCompilerActionInfo(project: Project, context: KobaltContext, compiler: ICompilerDescription,
isTest: Boolean, sourceDirectories: List<File>, sourceSuffixes: List<String>, buildDirectory: File)
: CompilerActionInfo {
copyResources(project, context, SourceSet.of(isTest))
val fullClasspath = dependencyManager.calculateDependencies(project, context,
scopes = if (isTest) {
listOf(Scope.COMPILE, Scope.COMPILEONLY, Scope.TEST)
} else {
listOf(Scope.COMPILE, Scope.COMPILEONLY)
})
File(project.directory, buildDirectory.path).mkdirs()
// Remove all the excluded dependencies from the classpath
var classpath = fullClasspath
// The classpath needs to contain $buildDirectory/classes as well so that projects that contain
// multiple languages can use classes compiled by the compiler run before them.
fun containsClassFiles(dir: File) =
KFiles.containsCertainFile(dir) {
it.isFile && it.name.endsWith("class")
}
// if (buildDirectory.exists()) {
if (containsClassFiles(buildDirectory)) {
classpath += FileDependency(buildDirectory.path)
}
val initialSourceDirectories = ArrayList<File>(sourceDirectories)
// Source directories from the contributors
val contributedSourceDirs =
if (isTest) {
context.pluginInfo.testSourceDirContributors.flatMap { it.testSourceDirectoriesFor(project, context) }
} else {
context.pluginInfo.sourceDirContributors.flatMap { it.sourceDirectoriesFor(project, context) }
}
initialSourceDirectories.addAll(contributedSourceDirs)
// Transform them with the interceptors, if any
val allSourceDirectories =
if (isTest) {
initialSourceDirectories
} else {
context.pluginInfo.sourceDirectoriesInterceptors.fold(initialSourceDirectories.toList(),
{ sd, interceptor -> interceptor.intercept(project, context, sd) })
}.filter {
File(project.directory, it.path).exists()
}.filter {
! KFiles.isResource(it.path)
}.distinctBy {
Paths.get(it.path)
}
// Now that we have all the source directories, find all the source files in them. Note that
// depending on the compiler's ability, sourceFiles can actually contain a list of directories
// instead of individual source files.
val projectDirectory = File(project.directory)
val sourceFiles =
if (compiler.canCompileDirectories) {
allSourceDirectories.map { File(projectDirectory, it.path).path }
} else {
files.findRecursively(projectDirectory, allSourceDirectories,
{ file -> sourceSuffixes.any { file.endsWith(it) } })
.map { File(projectDirectory, it).path }
}
// Special treatment if we are compiling Kotlin files and the project also has a java source
// directory. In this case, also pass that java source directory to the Kotlin compiler as is
// so that it can parse its symbols
// Note: this should actually be queried on the compiler object so that this method, which
// is compiler agnostic, doesn't hardcode Kotlin specific stuff
val extraSourceFiles = arrayListOf<String>()
fun containsJavaFiles(dir: File) =
KFiles.containsCertainFile(dir) {
it.isFile && it.name.endsWith("java")
}
if (sourceSuffixes.any { it.contains("kt")}) {
val directories = if (isTest) project.sourceDirectoriesTest else project.sourceDirectories
directories.forEach {
val javaDir = File(KFiles.joinDir(project.directory, it))
if (javaDir.exists() && containsJavaFiles(javaDir) && ! KFiles.isResource(javaDir.path)) {
extraSourceFiles.add(javaDir.path)
// Add all the source directories contributed as potential Java directories too
// (except our own)
context.pluginInfo.sourceDirContributors.forEach {
val sd = it.sourceDirectoriesFor(project, context).map { it.path }
.filter { ! it.contains("kotlin") }
if (! sd.contains("kotlin")) {
extraSourceFiles.addAll(sd)
}
}
}
}
}
val distinctSources = (sourceFiles + extraSourceFiles).distinctBy { File(it).toURI().normalize().path }
val allSources = distinctSources
.map { File(it).path }
.distinct()
.filter { File(it).exists() }
// Finally, alter the info with the compiler interceptors before returning it
val initialActionInfo = CompilerActionInfo(projectDirectory.path, classpath, allSources,
sourceSuffixes, buildDirectory, emptyList() /* the flags will be provided by flag contributors */,
emptyList(), context.internalContext.forceRecompile)
val result = context.pluginInfo.compilerInterceptors.fold(initialActionInfo, { ai, interceptor ->
interceptor.intercept(project, context, ai)
})
//
// friendPaths
//
val friendPaths = KFiles.joinDir(project.buildDirectory, KFiles.CLASSES_DIR)
return result
}
/**
* Copy the resources from a source directory to the build one
*/
private fun copyResources(project: Project, context: KobaltContext, sourceSet: SourceSet) {
val outputDir = sourceSet.outputDir
val variantSourceDirs = context.variant.resourceDirectories(project, sourceSet)
if (variantSourceDirs.isNotEmpty()) {
context.logger.log(project.name, 2, "Copying $sourceSet resources")
val absOutputDir = File(KFiles.joinDir(project.directory, project.buildDirectory, outputDir))
variantSourceDirs
.map { File(project.directory, it.path) }
.filter(File::exists)
.forEach {
context.logger.log(project.name, 2, "Copying from $it to $absOutputDir")
KFiles.copyRecursively(it, absOutputDir, replaceExisting = true)
}
} else {
context.logger.log(project.name, 2, "No resources to copy for $sourceSet")
}
}
fun sourceCompilerFlags(project: Project?, context: KobaltContext, info: CompilerActionInfo) : List<String> {
val adapters = context.pluginInfo.compilerFlagContributors.map {
val closure = { project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>
-> it.compilerFlagsFor(project, context, currentFlags, suffixesBeingCompiled) }
FlagContributor(it.flagPriority, closure)
}
return compilerFlags(project, context, info, adapters)
}
fun compilerFlags(project: Project?, context: KobaltContext, info: CompilerActionInfo,
adapters: List<FlagContributor>) : List<String> {
val result = arrayListOf<String>()
if (project != null) {
adapters.sortedBy { it.flagPriority }
adapters.forEach {
result.addAll(it.flagsFor(project, context, result, info.suffixesBeingCompiled))
}
}
return result
}
}

View file

@ -2,7 +2,7 @@ package com.beust.kobalt.internal
class DocUrl { class DocUrl {
companion object { companion object {
private const val HOST = "https://beust.com/kobalt/" private const val HOST = "http://beust.com/kobalt/"
private fun url(path: String) = HOST + path private fun url(path: String) = HOST + path
val PUBLISH_PLUGIN_URL = url("plug-ins/index.html#publishing") val PUBLISH_PLUGIN_URL = url("plug-ins/index.html#publishing")

View file

@ -1,101 +1,46 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.* import com.beust.kobalt.KobaltException
import com.beust.kobalt.misc.* import com.beust.kobalt.TaskResult
import com.beust.kobalt.misc.NamedThreadFactory
import com.beust.kobalt.misc.error
import com.beust.kobalt.misc.log
import com.google.common.collect.HashMultimap import com.google.common.collect.HashMultimap
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.util.* import java.util.*
import java.util.concurrent.* import java.util.concurrent.*
open class TaskResult2<T>(success: Boolean, testResult: TestResult? = null, open class TaskResult2<T>(success: Boolean, errorMessage: String?, val value: T) : TaskResult(success, errorMessage) {
errorMessage: String? = null, val value: T) : TaskResult(success, testResult, errorMessage) {
override fun toString() = com.beust.kobalt.misc.toString("TaskResult", "value", value, "success", success) override fun toString() = com.beust.kobalt.misc.toString("TaskResult", "value", value, "success", success)
} }
class Node<T>(val value: T) {
override fun hashCode() = value!!.hashCode()
override fun equals(other: Any?) : Boolean {
val result = if (other is Node<*>) other.value == value else false
return result
}
override fun toString() = value.toString()
}
class DynamicGraph<T> { class DynamicGraph<T> {
val VERBOSE = 3 val VERBOSE = 2
val values : Collection<T> get() = nodes.map { it.value } val values : Collection<T> get() = nodes.map { it.value }
val nodes = hashSetOf<PrivateNode<T>>() val nodes = hashSetOf<Node<T>>()
private val dependedUpon = HashMultimap.create<PrivateNode<T>, PrivateNode<T>>() private val dependedUpon = HashMultimap.create<Node<T>, Node<T>>()
private val dependingOn = HashMultimap.create<PrivateNode<T>, PrivateNode<T>>() private val dependingOn = HashMultimap.create<Node<T>, Node<T>>()
class PrivateNode<T>(val value: T) {
override fun hashCode() = value!!.hashCode()
override fun equals(other: Any?) : Boolean {
val result = if (other is PrivateNode<*>) other.value == value else false
return result
}
override fun toString() = value.toString()
}
companion object {
fun <T> transitiveClosure(root: T, childrenFor: (T) -> List<T>) : List<T> {
val result = arrayListOf<T>()
val seen = hashSetOf<T>()
val toProcess = arrayListOf<T>().apply {
add(root)
}
while (toProcess.any()) {
val newToProcess = arrayListOf<T>()
toProcess.forEach {
if (! seen.contains(it)) {
result.add(it)
newToProcess.addAll(childrenFor(it))
seen.add(it)
}
}
toProcess.clear()
toProcess.addAll(newToProcess)
}
return result
}
class Node<T>(val value: T, val children: List<Node<T>>) {
fun dump(root : Node<T> = this, indent: String = "") : String {
return StringBuffer().apply {
append(indent).append(root.value).append("\n")
root.children.forEach {
append(dump(it, indent + " "))
}
}.toString()
}
}
fun <T> transitiveClosureGraph(roots: List<T>, childrenFor: (T) -> List<T>,
filter: (T) -> Boolean): List<Node<T>>
= roots.map { transitiveClosureGraph(it, childrenFor, filter) }
fun <T> transitiveClosureGraph(root: T, childrenFor: (T) -> List<T>,
filter: (T) -> Boolean = { t: T -> true },
seen: HashSet<T> = hashSetOf()) : Node<T> {
val children = arrayListOf<Node<T>>()
childrenFor(root).filter(filter).forEach { child ->
if (! seen.contains(child)) {
seen.add(child)
val c = transitiveClosureGraph(child, childrenFor, filter, seen)
children.add(c)
}
}
return Node(root, children)
}
}
fun childrenOf(v: T) : Collection<T> = dependedUpon[PrivateNode(v)].map { it.value }
fun transitiveClosure(root: T)
= transitiveClosure(root) { element -> dependedUpon[PrivateNode(element)].map { it.value } }
fun addNode(t: T) = synchronized(nodes) { fun addNode(t: T) = synchronized(nodes) {
nodes.add(PrivateNode(t)) nodes.add(Node(t))
} }
fun removeNode(t: T) = synchronized(nodes) { fun removeNode(t: T) = synchronized(nodes) {
kobaltLog(VERBOSE, " Removing node $t") log(VERBOSE, " Removing $t")
PrivateNode(t).let { node -> Node(t).let { node ->
nodes.remove(node) nodes.remove(node)
dependingOn.removeAll(node) dependingOn.removeAll(node)
val set = dependedUpon.keySet() val set = dependedUpon.keySet()
val toReplace = arrayListOf<Pair<PrivateNode<T>, Collection<PrivateNode<T>>>>() val toReplace = arrayListOf<Pair<Node<T>, Collection<Node<T>>>>()
set.forEach { du -> set.forEach { du ->
val l = ArrayList(dependedUpon[du]) val l = ArrayList(dependedUpon[du])
l.remove(node) l.remove(node)
@ -111,10 +56,10 @@ class DynamicGraph<T> {
* Make "from" depend on "to" ("from" is no longer free). * Make "from" depend on "to" ("from" is no longer free).
*/ */
fun addEdge(from: T, to: T) { fun addEdge(from: T, to: T) {
val fromNode = PrivateNode(from) val fromNode = Node(from)
nodes.add(fromNode) nodes.add(fromNode)
val toNode = PrivateNode(to) val toNode = Node(to)
nodes.add(PrivateNode(to)) nodes.add(Node(to))
dependingOn.put(toNode, fromNode) dependingOn.put(toNode, fromNode)
dependedUpon.put(fromNode, toNode) dependedUpon.put(fromNode, toNode)
} }
@ -130,7 +75,6 @@ class DynamicGraph<T> {
} }
} }
val result = nodes.map { it.value }.filter { !nonFree.contains(it) }.toHashSet() val result = nodes.map { it.value }.filter { !nonFree.contains(it) }.toHashSet()
kobaltLog(VERBOSE, " Free nodes: $result")
return result return result
} }
} }
@ -138,7 +82,7 @@ class DynamicGraph<T> {
fun dump() : String { fun dump() : String {
val result = StringBuffer() val result = StringBuffer()
result.append("************ Graph dump ***************\n") result.append("************ Graph dump ***************\n")
val free = arrayListOf<PrivateNode<T>>() val free = arrayListOf<Node<T>>()
nodes.forEach { node -> nodes.forEach { node ->
val d = dependedUpon.get(node) val d = dependedUpon.get(node)
if (d == null || d.isEmpty()) { if (d == null || d.isEmpty()) {
@ -163,8 +107,6 @@ interface IWorker<T> : Callable<TaskResult2<T>> {
*/ */
// val tasks : List<T> // val tasks : List<T>
val name: String
/** /**
* @return the priority of this task. * @return the priority of this task.
*/ */
@ -183,18 +125,11 @@ interface IThreadWorkerFactory<T> {
fun createWorkers(nodes: Collection<T>) : List<IWorker<T>> fun createWorkers(nodes: Collection<T>) : List<IWorker<T>>
} }
class DynamicGraphExecutor<T>(val graph : DynamicGraph<T>, val factory: IThreadWorkerFactory<T>, class DynamicGraphExecutor<T>(val graph : DynamicGraph<T>, val factory: IThreadWorkerFactory<T>) {
val threadCount: Int = 1) { val executor = Executors.newFixedThreadPool(5, NamedThreadFactory("DynamicGraphExecutor"))
val executor : ExecutorService
= Executors.newFixedThreadPool(threadCount, NamedThreadFactory("DynamicGraphExecutor"))
val completion = ExecutorCompletionService<TaskResult2<T>>(executor) val completion = ExecutorCompletionService<TaskResult2<T>>(executor)
data class HistoryLog(val name: String, val timestamp: Long, val threadId: Long, val start: Boolean) fun run() : Int {
val historyLog = arrayListOf<HistoryLog>()
val threadIds = ConcurrentHashMap<Long, Long>()
fun run() : TaskResult {
try { try {
return run2() return run2()
} finally { } finally {
@ -202,31 +137,14 @@ class DynamicGraphExecutor<T>(val graph : DynamicGraph<T>, val factory: IThreadW
} }
} }
private fun run2() : TaskResult { private fun run2() : Int {
var running = 0 var running = 0
var gotError = false
val nodesRun = hashSetOf<T>() val nodesRun = hashSetOf<T>()
var failedResult: TaskResult? = null var newFreeNodes = HashSet<T>(graph.freeNodes)
val newFreeNodes = HashSet<T>(graph.freeNodes) while (! gotError && (running > 0 || newFreeNodes.size > 0)) {
while (failedResult == null && (running > 0 || newFreeNodes.size > 0)) {
nodesRun.addAll(newFreeNodes) nodesRun.addAll(newFreeNodes)
val callables : List<IWorker<T>> = factory.createWorkers(newFreeNodes).map { val callables : List<IWorker<T>> = factory.createWorkers(newFreeNodes)
it -> object: IWorker<T> {
override val priority: Int
get() = it.priority
override val name: String get() = it.name
override fun call(): TaskResult2<T> {
val threadId = Thread.currentThread().id
historyLog.add(HistoryLog(it.name, System.currentTimeMillis(), threadId,
start = true))
threadIds.put(threadId, threadId)
val result = it.call()
historyLog.add(HistoryLog(it.name, System.currentTimeMillis(), Thread.currentThread().id,
start = false))
return result
}
}
}
callables.forEach { completion.submit(it) } callables.forEach { completion.submit(it) }
running += callables.size running += callables.size
@ -236,19 +154,17 @@ class DynamicGraphExecutor<T>(val graph : DynamicGraph<T>, val factory: IThreadW
running-- running--
if (taskResult.success) { if (taskResult.success) {
nodesRun.add(taskResult.value) nodesRun.add(taskResult.value)
kobaltLog(3, "Task succeeded: $taskResult") log(2, "Task succeeded: $taskResult")
graph.removeNode(taskResult.value) graph.removeNode(taskResult.value)
newFreeNodes.clear() newFreeNodes.clear()
newFreeNodes.addAll(graph.freeNodes.minus(nodesRun)) newFreeNodes.addAll(graph.freeNodes.minus(nodesRun))
} else { } else {
kobaltLog(3, "Task failed: $taskResult") log(2, "Task failed: $taskResult")
newFreeNodes.clear() newFreeNodes.clear()
if (failedResult == null) { gotError = true
failedResult = taskResult
}
} }
} catch(ex: TimeoutException) { } catch(ex: TimeoutException) {
kobaltLog(3, "Time out") log(2, "Time out")
} catch(ex: Exception) { } catch(ex: Exception) {
val ite = ex.cause val ite = ex.cause
if (ite is InvocationTargetException) { if (ite is InvocationTargetException) {
@ -256,125 +172,15 @@ class DynamicGraphExecutor<T>(val graph : DynamicGraph<T>, val factory: IThreadW
throw (ex.cause as InvocationTargetException).targetException throw (ex.cause as InvocationTargetException).targetException
} else { } else {
error("Error: ${ite.cause?.message}", ite.cause) error("Error: ${ite.cause?.message}", ite.cause)
failedResult = TaskResult(success = false, errorMessage = ite.cause?.message) gotError = true
} }
} else { } else {
error("Error: ${ex.message}", ex) error("Error: ${ex.message}", ex)
failedResult = TaskResult(success = false, errorMessage = ex.message) gotError = true
} }
} }
} }
return if (failedResult != null) failedResult else TaskResult() return if (gotError) 1 else 0
}
fun dumpHistory() {
kobaltLog(1, "Thread report")
val table = AsciiTable.Builder()
.columnWidth(11)
threadIds.keys.forEach {
table.columnWidth(24)
}
table.header("Time (sec)")
threadIds.keys.forEach {
table.header("Thread " + it.toString())
}
fun toSeconds(millis: Long) = (millis / 1000).toInt().toString()
fun displayCompressedLog(table: AsciiTable.Builder) : AsciiTable.Builder {
data class CompressedLog(val timestamp: Long, val threadMap: HashMap<Long, String>)
fun compressLog(historyLog: List<HistoryLog>): ArrayList<CompressedLog> {
val compressed = arrayListOf<CompressedLog>()
var currentLog: CompressedLog? = null
val projectStart = hashMapOf<String, Long>()
fun toName(hl: HistoryLog) : String {
var duration = ""
if (! hl.start) {
val start = projectStart[hl.name]
if (start != null) {
duration = " (" + ((hl.timestamp - start) / 1000)
.toInt().toString() + ")"
} else {
kobaltLog(1, "DONOTCOMMIT")
}
}
return hl.name + duration
}
historyLog.forEach { hl ->
kobaltLog(1, "CURRENT LOG: " + currentLog + " HISTORY LINE: " + hl)
if (hl.start) {
projectStart[hl.name] = hl.timestamp
}
if (currentLog == null) {
currentLog = CompressedLog(hl.timestamp, hashMapOf(hl.threadId to hl.name))
} else currentLog?.let { cl ->
if (! hl.start || hl.timestamp - cl.timestamp < 1000) {
kobaltLog(1, " CURRENT LOG IS WITHING ONE SECOND: $hl")
cl.threadMap[hl.threadId] = toName(hl)
} else {
kobaltLog(1, " ADDING COMPRESSED LINE $cl")
compressed.add(cl)
currentLog = CompressedLog(hl.timestamp, hashMapOf(hl.threadId to toName(hl)))
}
}
}
return compressed
}
compressLog(historyLog).forEach {
val row = arrayListOf<String>()
row.add(toSeconds(it.timestamp))
it.threadMap.values.forEach {
row.add(it)
}
table.addRow(row)
}
return table
}
fun displayRegularLog(table: AsciiTable.Builder) : AsciiTable.Builder {
if (historyLog.any()) {
if (historyLog[0] != null) {
val start = historyLog[0].timestamp
val projectStart = ConcurrentHashMap<String, Long>()
historyLog.forEach { line ->
val row = arrayListOf<String>()
row.add(toSeconds(line.timestamp - start))
threadIds.keys.forEach {
if (line.threadId == it) {
var duration = ""
if (line.start) {
projectStart[line.name] = line.timestamp
} else {
val projectStart = projectStart[line.name]
if (projectStart != null) {
duration = " (" + ((line.timestamp - projectStart) / 1000)
.toInt().toString() + ")"
} else {
warn("Couldn't determine project start: " + line.name)
}
}
row.add((line.name + duration))
} else {
row.add("")
}
}
table.addRow(row)
}
} else {
warn("Couldn't find historyLog")
}
}
return table
}
kobaltLog(1, displayRegularLog(table).build())
} }
} }
@ -393,12 +199,11 @@ fun main(argv: Array<String>) {
return nodes.map { return nodes.map {
object: IWorker<String> { object: IWorker<String> {
override fun call(): TaskResult2<String>? { override fun call(): TaskResult2<String>? {
kobaltLog(1, " Running worker $it") log(1, " Running worker $it")
return TaskResult2(true, value = it) return TaskResult2(true, null, it)
} }
override val priority: Int get() = 0 override val priority: Int get() = 0
override val name: String = "workerName"
} }
} }
} }

View file

@ -3,8 +3,8 @@ package com.beust.kobalt.internal
import com.beust.kobalt.* import com.beust.kobalt.*
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
import com.google.common.annotations.VisibleForTesting import com.google.common.annotations.VisibleForTesting
import com.google.inject.Inject
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -15,113 +15,49 @@ import java.util.*
abstract class GenericTestRunner: ITestRunnerContributor { abstract class GenericTestRunner: ITestRunnerContributor {
abstract val dependencyName : String abstract val dependencyName : String
abstract val mainClass: String abstract val mainClass: String
abstract val annotationPackage: String abstract fun args(project: Project, classpath: List<IClasspathDependency>, testConfig: TestConfig) : List<String>
abstract val runnerName: String
open var shortMessage: String? = null
open var longMessage: String? = null
@Inject
private lateinit var jvm: Jvm
abstract fun args(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
testConfig: TestConfig) : List<String>
open fun onFinish(project: Project) {}
open val extraClasspath: List<String> = emptyList()
open fun filterTestClasses(project: Project, context: KobaltContext, classes: List<String>) : List<String> = classes
override fun run(project: Project, context: KobaltContext, configName: String, override fun run(project: Project, context: KobaltContext, configName: String,
classpath: List<IClasspathDependency>) : TaskResult { classpath: List<IClasspathDependency>)
val tr = runTests(project, context, classpath, configName) = TaskResult(runTests(project, context, classpath, configName))
return TaskResult(tr.success, testResult = tr)
}
override fun affinity(project: Project, context: KobaltContext) : Int { override fun affinity(project: Project, context: KobaltContext) =
val result = if (project.testDependencies.any { it.id.contains(dependencyName)}) IAffinity.DEFAULT_POSITIVE_AFFINITY
if (project.testDependencies.any { it.id.contains(dependencyName) }) IAffinity.DEFAULT_POSITIVE_AFFINITY
else 0 else 0
return result
}
protected fun findTestClasses(project: Project, context: KobaltContext, testConfig: TestConfig): List<String> { protected fun findTestClasses(project: Project, testConfig: TestConfig): List<String> {
val testClassDir = KFiles.joinDir(project.buildDirectory, KFiles.TEST_CLASSES_DIR) val path = KFiles.joinDir(project.buildDirectory, KFiles.TEST_CLASSES_DIR).apply {
val path = testClassDir.apply {
File(this).mkdirs() File(this).mkdirs()
} }
val files = IFileSpec.GlobSpec(toClassPaths(testConfig.testIncludes)) val result = IFileSpec.GlobSpec(toClassPaths(testConfig.testIncludes))
.toFiles(project.directory, path, testConfig.testExcludes.map { Glob(it) }) .toFiles(project.directory, path, testConfig.testExcludes.map {
val testClasses = files Glob(it)
.map { }).map {
File(KFiles.joinDir(project.directory, testClassDir, it.path)) it.toString().replace("/", ".").replace("\\", ".").replace(".class", "")
} }
val result = testClasses.map {
val prefix = KFiles.joinDir(project.directory, testClassDir)
val className = it.toString().substring(prefix.length + 1)
.replace("/", ".").replace("\\", ".").replace(".class", "")
Pair(it, className)
}
// .filter {
// val result = acceptClass(it.first, it.second, testClasspath, File(testClassDir))
// result
// }
context.logger.log(project.name, 2, "Found ${result.size} test classes") log(2, "Found ${result.size} test classes")
return filterTestClasses(project, context, result.map { it.second }) return result
} }
/**
* Accept the given class if it contains an annotation of the current test runner's package. Annotations
* are looked up on both the classes and methods.
*/
// private fun acceptClass(cf: File, className: String, testClasspath: List<IClasspathDependency>,
// testClassDir: File): Boolean {
// val cp = (testClasspath.map { it.jarFile.get() } + listOf(testClassDir)).map { it.toURI().toURL() }
// try {
// val cls = URLClassLoader(cp.toTypedArray()).loadClass(className)
// val ann = cls.annotations.filter {
// val qn = it.annotationClass.qualifiedName
// qn != null && qn.contains(annotationPackage)
// }
// if (ann.any()) {
// return true
// } else {
// val ann2 = cls.declaredMethods.flatMap { it.declaredAnnotations.toList() }.filter { it.toString()
// .contains(annotationPackage)}
// if (ann2.any()) {
// val a0 = ann2[0]
// return true
// }
// }
// } catch(ex: Throwable) {
// println("Exception: " + ex.message)
// return false
// }
// return false
// }
private fun toClassPaths(paths: List<String>): ArrayList<String> = private fun toClassPaths(paths: List<String>): ArrayList<String> =
paths.map { if (it.endsWith("class")) it else it + "class" }.toCollection(ArrayList()) paths.map { if (it.endsWith("class")) it else it + "class" }.toCollection(ArrayList())
/** /**
* @return true if all the tests passed * @return true if all the tests passed
*/ */
open fun runTests(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>, fun runTests(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
configName: String) : TestResult { configName: String) : Boolean {
var result = false var result = false
context.logger.log(project.name, 1, "Running tests with $runnerName")
val testConfig = project.testConfigs.firstOrNull { it.name == configName } val testConfig = project.testConfigs.firstOrNull { it.name == configName }
var errorCode = -1
if (testConfig != null) { if (testConfig != null) {
val args = args(project, context, classpath, testConfig) val args = args(project, classpath, testConfig)
if (args.size > 0) { if (args.size > 0) {
val java = jvm.javaExecutable val java = JavaInfo.create(File(SystemProperties.javaBase)).javaExecutable
val jvmArgs = calculateAllJvmArgs(project, context, testConfig, classpath, val jvmArgs = calculateAllJvmArgs(project, context, testConfig, classpath,
Kobalt.INJECTOR.getInstance (PluginInfo::class.java)) Kobalt.INJECTOR.getInstance (PluginInfo::class.java))
val allArgs = arrayListOf<String>().apply { val allArgs = arrayListOf<String>().apply {
@ -134,28 +70,24 @@ abstract class GenericTestRunner: ITestRunnerContributor {
val pb = ProcessBuilder(allArgs) val pb = ProcessBuilder(allArgs)
pb.directory(File(project.directory)) pb.directory(File(project.directory))
pb.inheritIO() pb.inheritIO()
context.logger.log(project.name, 2, "Running tests with classpath size ${classpath.size}") log(2, "Running tests with classpath size ${classpath.size}")
context.logger.log(project.name, 2, "Launching " + allArgs.joinToString(" ")) log(2, "Launching " + allArgs.joinToString(" "))
val process = pb.start() val process = pb.start()
errorCode = process.waitFor() val errorCode = process.waitFor()
if (errorCode == 0) {
log(1, "All tests passed")
} else {
log(1, "Test failures")
}
result = result || errorCode == 0 result = result || errorCode == 0
} else { } else {
context.logger.log(project.name, 1, " No tests to run") log(2, "Couldn't find any test classes")
result = true result = true
} }
} else { } else {
throw KobaltException("Couldn't find a test configuration named \"$configName\"") throw KobaltException("Couldn't find a test configuration named \"$configName\"")
} }
return result
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)
} }
/* /*
@ -164,13 +96,11 @@ abstract class GenericTestRunner: ITestRunnerContributor {
@VisibleForTesting @VisibleForTesting
fun calculateAllJvmArgs(project: Project, context: KobaltContext, fun calculateAllJvmArgs(project: Project, context: KobaltContext,
testConfig: TestConfig, classpath: List<IClasspathDependency>, pluginInfo: IPluginInfo) : List<String> { testConfig: TestConfig, classpath: List<IClasspathDependency>, pluginInfo: IPluginInfo) : List<String> {
val fullClasspath = classpath.map { it.jarFile.get().absolutePath } + extraClasspath
// Default JVM args // Default JVM args
val jvmFlags = arrayListOf<String>().apply { val jvmFlags = arrayListOf<String>().apply {
addAll(testConfig.jvmArgs) addAll(testConfig.jvmArgs)
add("-ea")
add("-classpath") add("-classpath")
add(fullClasspath.joinToString(File.pathSeparator)) add(classpath.map { it.jarFile.get().absolutePath }.joinToString(File.pathSeparator))
} }
// JVM flags from the contributors // JVM flags from the contributors
@ -179,7 +109,7 @@ abstract class GenericTestRunner: ITestRunnerContributor {
} }
// JVM flags from the interceptors (these overwrite flags instead of just adding to the list) // JVM flags from the interceptors (these overwrite flags instead of just adding to the list)
val result = ArrayList(jvmFlags + jvmFlagsFromContributors) var result = ArrayList(jvmFlags + jvmFlagsFromContributors)
pluginInfo.testJvmFlagInterceptors.forEach { pluginInfo.testJvmFlagInterceptors.forEach {
val newFlags = it.testJvmFlagsFor(project, context, result) val newFlags = it.testJvmFlagsFor(project, context, result)
result.clear() result.clear()
@ -187,8 +117,7 @@ abstract class GenericTestRunner: ITestRunnerContributor {
} }
if (result.any()) { if (result.any()) {
context.logger.log(project.name, 2, log(2, "Final JVM test flags after running the contributors and interceptors: $result")
"Final JVM test flags after running the contributors and interceptors: $result")
} }
return result return result

View file

@ -1,35 +0,0 @@
package com.beust.kobalt.internal
/**
* Generic operations on graph-like structures.
*/
object GraphUtil {
/**
* Apply the operation in `closure` to all the nodes in the tree.
*/
fun <T> map(roots: List<T>, children: (T) -> List<T>, closure: (T) -> Unit) {
roots.forEach {
closure(it)
map(children(it), children, closure)
}
}
/**
* Display each node in the roots by calling the `display` function on each of them.
*/
fun <T> displayGraph(roots: List<T>,
children: (T) -> List<T>,
display: (node: T, indent: String) -> Unit) {
fun pd(node: T, indent: String) {
display(node, indent)
children(node).forEach {
pd(it, indent + " ")
}
}
roots.forEach {
pd(it, "")
}
}
}

View file

@ -7,7 +7,7 @@ import com.beust.kobalt.Variant
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.google.inject.Inject import com.google.inject.Inject
@ -19,17 +19,16 @@ import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import java.util.* import java.util.*
data class TaskInfo(val taskName: String, var inputChecksum: String? = null, var outputChecksum: String? = null)
class BuildInfo(var tasks: List<TaskInfo>)
/** /**
* Manage the file .kobalt/buildInfo.json, which keeps track of input and output checksums to manage * Manage the file .kobalt/buildInfo.json, which keeps track of input and output checksums to manage
* incremental builds. * incremental builds.
*/ */
class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileName : String) { class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileName : String) {
private data class TaskInfo(val taskName: String, var inputChecksum: String? = null,
var outputChecksum: String? = null)
private class BuildInfo(var tasks: List<TaskInfo>)
interface IFactory { interface IFactory {
fun create(@Assisted fileName: String = IncrementalManager.BUILD_INFO_FILE) : IncrementalManager fun create(@Assisted fileName: String = IncrementalManager.BUILD_INFO_FILE) : IncrementalManager
} }
@ -55,7 +54,6 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
private fun save(map: Map<String, TaskInfo>) { private fun save(map: Map<String, TaskInfo>) {
val bi = BuildInfo(map.values.toList()) val bi = BuildInfo(map.values.toList())
val json = GsonBuilder().setPrettyPrinting().create().toJson(bi) val json = GsonBuilder().setPrettyPrinting().create().toJson(bi)
Files.write(Paths.get(fileName), json.toByteArray(Charset.defaultCharset())) Files.write(Paths.get(fileName), json.toByteArray(Charset.defaultCharset()))
} }
@ -63,33 +61,24 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
= taskInfos.getOrPut(taskName, { -> TaskInfo(taskName) }) = taskInfos.getOrPut(taskName, { -> TaskInfo(taskName) })
fun saveInputChecksum(taskName: String, inputChecksum: String) { fun saveInputChecksum(taskName: String, inputChecksum: String) {
synchronized(BUILD_INFO_FILE) { with(taskInfos()) {
with(taskInfos()) { taskInfoFor(this, taskName).inputChecksum = inputChecksum
taskInfoFor(this, taskName).inputChecksum = inputChecksum save(this)
save(this)
}
} }
} }
fun inputChecksumFor(taskName: String) : String? = fun inputChecksumFor(taskName: String) : String? =
synchronized(BUILD_INFO_FILE) {
taskInfoFor(taskInfos(), taskName).inputChecksum taskInfoFor(taskInfos(), taskName).inputChecksum
}
fun saveOutputChecksum(taskName: String, outputChecksum: String) { fun saveOutputChecksum(taskName: String, outputChecksum: String) {
synchronized(BUILD_INFO_FILE) { with(taskInfos()) {
with(taskInfos()) { taskInfoFor(this, taskName).outputChecksum = outputChecksum
taskInfoFor(this, taskName).outputChecksum = outputChecksum save(this)
save(this)
}
} }
} }
fun outputChecksumFor(taskName: String) : String? = fun outputChecksumFor(taskName: String) : String? =
synchronized(BUILD_INFO_FILE) {
taskInfoFor(taskInfos(), taskName).outputChecksum taskInfoFor(taskInfos(), taskName).outputChecksum
}
/** /**
* @param method is assumed to return an IncrementalTaskInfo. * @param method is assumed to return an IncrementalTaskInfo.
* @return a closure that invokes that method and decide whether to run the task or not based * @return a closure that invokes that method and decide whether to run the task or not based
@ -136,8 +125,7 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
if (outputChecksum == taskOutputChecksum) { if (outputChecksum == taskOutputChecksum) {
upToDate = true upToDate = true
} else { } else {
logIncremental(LEVEL, "Incremental task $taskName output is out of date" + logIncremental(LEVEL, "Incremental task $taskName output is out of date, running it")
" (different output checksums), running it")
} }
} }
} else { } else {
@ -145,7 +133,7 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
logIncremental(LEVEL, "Project ${project.name} depends on dirty project, running $taskName") logIncremental(LEVEL, "Project ${project.name} depends on dirty project, running $taskName")
} else { } else {
logIncremental(LEVEL, "Incremental task $taskName input is out of date, running it" logIncremental(LEVEL, "Incremental task $taskName input is out of date, running it"
+ " (different input checksums old: $inputChecksum new: ${iti.inputChecksum()})") + " old: $inputChecksum new: ${iti.inputChecksum()}")
} }
project.projectExtra.isDirty = true project.projectExtra.isDirty = true
} }
@ -182,5 +170,5 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
} }
val LEVEL = 2 val LEVEL = 2
private fun logIncremental(level: Int, s: String) = kobaltLog(level, " INC - $s") private fun logIncremental(level: Int, s: String) = log(level, " INC - $s")
} }

View file

@ -1,152 +0,0 @@
package com.beust.kobalt.internal
import com.beust.jcommander.JCommander
import com.beust.jcommander.Parameter
import com.beust.kobalt.TestConfig
import com.beust.kobalt.api.IAffinity
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltLogger
import com.google.inject.Inject
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.engine.reporting.ReportEntry
import org.junit.platform.engine.support.descriptor.MethodSource
import org.junit.platform.launcher.LauncherDiscoveryRequest
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestPlan
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import java.io.File
import java.nio.file.Paths
/**
* Runner for JUnit 5 tests. This class also contains a main() entry point since JUnit 5 no longer supplies one.
*/
class JUnit5Runner @Inject constructor(kFiles: KFiles) : GenericTestRunner() {
override val dependencyName = "jupiter"
override val annotationPackage = "org.junit.jupiter.api"
override val mainClass = "com.beust.kobalt.internal.JUnit5RunnerKt"
override val runnerName = "JUnit 5"
override fun affinity(project: Project, context: KobaltContext) : Int {
val result =
if (project.testDependencies.any { it.id.contains("junit5") || it.id.contains("jupiter") })
IAffinity.DEFAULT_POSITIVE_AFFINITY + 100
else 0
return result
}
override fun args(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>, testConfig: TestConfig): List<String> {
val testClassDir = KFiles.joinDir(project.buildDirectory, KFiles.TEST_CLASSES_DIR)
val classDir = KFiles.joinDir(project.buildDirectory, KFiles.CLASSES_DIR)
val args = listOf("--testClassDir", testClassDir,
"--classDir", classDir,
"--log", KobaltLogger.LOG_LEVEL.toString())
return args
}
override val extraClasspath = kFiles.kobaltJar
}
private class Args {
@Parameter(names = arrayOf("--log"))
var log: Int = 1
@Parameter(names = arrayOf("--testClassDir"))
var testClassDir: String = "kobaltBuild/test-classes"
@Parameter(names = arrayOf("--classDir"))
var classDir: String = "kobaltBuild/classes"
}
fun main(argv: Array<String>) {
val args = Args()
val jc = JCommander(args)
jc.parse(*argv)
val testClassDir = File(args.testClassDir).absolutePath
val classDir = File(args.classDir).absolutePath
val request : LauncherDiscoveryRequest = LauncherDiscoveryRequestBuilder()
.selectors(DiscoverySelectors.selectClasspathRoots(setOf(
Paths.get(testClassDir),
Paths.get(classDir)
)))
.selectors(DiscoverySelectors.selectDirectory(testClassDir))
.build()
fun testName(id: TestIdentifier) : String? {
val result =
if (id.source.isPresent) {
val source = id.source.get()
if (source is MethodSource) {
source.className + "." + source.methodName
} else {
null
}
} else {
null
}
return result
}
var passed = 0
var failed = 0
var skipped = 0
var aborted = 0
fun log(level: Int, s: String) {
if (level <= args.log) println(s)
}
val listener = object: TestExecutionListener {
override fun executionFinished(testIdentifier: TestIdentifier, testExecutionResult: TestExecutionResult) {
val testName = testName(testIdentifier)
if (testName != null) {
when(testExecutionResult.status) {
TestExecutionResult.Status.FAILED -> {
log(1, "FAILED: $testName, reason: " + testExecutionResult.throwable.get().toString())
failed++
}
TestExecutionResult.Status.ABORTED -> {
log(1, "ABORTED: $testName, reason: " + testExecutionResult.throwable.get().toString())
aborted++
}
TestExecutionResult.Status.SUCCESSFUL -> {
log(2, "PASSED: $testName")
passed++
} else -> {
}
}
}
}
override fun executionSkipped(testIdentifier: TestIdentifier, reason: String) {
testName(testIdentifier)?.let {
log(1, "Skipping $it because $reason")
skipped++
}
}
override fun executionStarted(testIdentifier: TestIdentifier) {
testName(testIdentifier)?.let {
log(2, "Starting $it")
}
}
override fun testPlanExecutionStarted(testPlan: TestPlan?) {}
override fun dynamicTestRegistered(testIdentifier: TestIdentifier?) {}
override fun reportingEntryPublished(testIdentifier: TestIdentifier?, entry: ReportEntry?) {}
override fun testPlanExecutionFinished(testPlan: TestPlan?) {}
}
LauncherFactory.create().execute(request, listener)
log(1, "TEST RESULTS: $passed PASSED, $failed FAILED, $skipped SKIPPED, $aborted ABORTED")
}

View file

@ -2,31 +2,15 @@ package com.beust.kobalt.internal
import com.beust.kobalt.TestConfig import com.beust.kobalt.TestConfig
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.maven.DependencyManager
import com.google.inject.Inject
import java.lang.reflect.Modifier
import java.net.URLClassLoader
open class JUnitRunner() : GenericTestRunner() { open class JUnitRunner() : GenericTestRunner() {
override val mainClass = "org.junit.runner.JUnitCore" override val mainClass = "org.junit.runner.JUnitCore"
override val annotationPackage = "org.junit"
override val dependencyName = "junit" override val dependencyName = "junit"
override val runnerName = "JUnit 4"
override fun args(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
testConfig: TestConfig) = findTestClasses(project, context, testConfig)
@Inject
lateinit var dependencyManager: DependencyManager
override fun filterTestClasses(project: Project, context: KobaltContext, classes: List<String>) : List<String> {
val deps = dependencyManager.testDependencies(project, context)
val cl = URLClassLoader(deps.map { it.jarFile.get().toURI().toURL() }.toTypedArray())
return classes.filter { !Modifier.isAbstract(cl.loadClass(it).modifiers) }
}
override fun args(project: Project, classpath: List<IClasspathDependency>, testConfig: TestConfig)
= findTestClasses(project, testConfig)
} }

View file

@ -15,36 +15,47 @@ import java.util.*
* Also validates the classpath and run all the contributors. * Also validates the classpath and run all the contributors.
*/ */
class JvmCompiler @Inject constructor(val dependencyManager: DependencyManager) { class JvmCompiler @Inject constructor(val dependencyManager: DependencyManager) {
/** /**
* Take the given CompilerActionInfo and enrich it with all the applicable contributors and * Take the given CompilerActionInfo and enrich it with all the applicable contributors and
* then pass it to the ICompilerAction. * then pass it to the ICompilerAction.
*/ */
fun doCompile(project: Project?, context: KobaltContext?, action: ICompilerAction, info: CompilerActionInfo, fun doCompile(project: Project?, context: KobaltContext?, action: ICompilerAction, info: CompilerActionInfo)
flags: List<String>): TaskResult { : TaskResult {
// Dependencies // Dependencies
val allDependencies = (info.dependencies + dependencyManager.calculateDependencies(project, context!!, val allDependencies = (info.dependencies
passedDependencies = info.dependencies)) + dependencyManager.calculateDependencies(project, context!!, allDependencies = info.dependencies))
.distinct() .distinct()
// Plugins that add flags to the compiler // Plugins that add flags to the compiler
val contributorFlags : List<String> = if (project != null) flags else emptyList() val currentFlags = arrayListOf<String>().apply { addAll(info.compilerArgs) }
val contributorFlags : List<String> = if (project != null) {
val contributors = context.pluginInfo.compilerFlagContributors
contributors.sortBy { it.flagPriority }
context.pluginInfo.compilerFlagContributors.forEach {
currentFlags.addAll(it.flagsFor(project, context, currentFlags, info.suffixesBeingCompiled))
}
currentFlags
} else {
emptyList()
}
val addedFlags = contributorFlags + ArrayList(info.compilerArgs) val addedFlags = contributorFlags + ArrayList(info.compilerArgs)
validateClasspath(allDependencies.map { it.jarFile.get().absolutePath }) validateClasspath(allDependencies.map { it.jarFile.get().absolutePath })
return action.compile(project, info.copy(dependencies = allDependencies, compilerArgs = addedFlags)) return action.compile(project?.name, info.copy(dependencies = allDependencies, compilerArgs = addedFlags))
} }
private fun validateClasspath(cp: List<String>) { private fun validateClasspath(cp: List<String>) {
cp.forEach { cp.forEach {
if (! File(it).exists()) { if (! File(it).exists()) {
throw KobaltException("Invalid classpath: couldn't find $it") throw KobaltException("Couldn't find $it")
} }
} }
} }
} }
interface ICompilerAction { interface ICompilerAction {
fun compile(project: Project?, info: CompilerActionInfo): TaskResult fun compile(projectName: String?, info: CompilerActionInfo): TaskResult
} }

View file

@ -9,11 +9,11 @@ import com.beust.kobalt.api.annotation.ExportedProjectProperty
import com.beust.kobalt.api.annotation.IncrementalTask import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.Md5 import com.beust.kobalt.maven.Md5
import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.error import com.beust.kobalt.misc.log
import com.beust.kobalt.misc.warn import com.beust.kobalt.misc.warn
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -21,21 +21,24 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
/** /**
* This plug-in takes care of compilation: it declares several common tasks ("compile", "compileTest") * This plug-in takes care of compilation: it declares a bunch of tasks ("compile", "compileTest") and
* and picks up all the compiler contributors in order to run them whenever a compilation is requested. * and picks up all the compiler contributors in order to run them whenever a compilation is requested.
*/ */
@Singleton @Singleton
open class JvmCompilerPlugin @Inject constructor( open class JvmCompilerPlugin @Inject constructor(
open val localRepo: LocalRepo,
open val files: KFiles, open val files: KFiles,
open val dependencyManager: DependencyManager, open val dependencyManager: DependencyManager,
open val executors: KobaltExecutors, open val executors: KobaltExecutors,
open val taskContributor : TaskContributor, open val taskContributor : TaskContributor)
val compilerUtils: CompilerUtils)
: BasePlugin(), ISourceDirectoryContributor, IProjectContributor, ITaskContributor by taskContributor { : BasePlugin(), ISourceDirectoryContributor, IProjectContributor, ITaskContributor by taskContributor {
companion object { companion object {
val PLUGIN_NAME = "JvmCompiler" val PLUGIN_NAME = "JvmCompiler"
@ExportedProjectProperty(doc = "Projects this project depends on", type = "List<ProjectDescription>")
const val DEPENDENT_PROJECTS = "dependentProjects"
@ExportedProjectProperty(doc = "Compiler args", type = "List<String>") @ExportedProjectProperty(doc = "Compiler args", type = "List<String>")
const val COMPILER_ARGS = "compilerArgs" const val COMPILER_ARGS = "compilerArgs"
@ -55,6 +58,13 @@ open class JvmCompilerPlugin @Inject constructor(
override fun accept(project: Project) = true override fun accept(project: Project) = true
/**
* Log with a project.
*/
protected fun lp(project: Project, s: String) {
log(2, "${project.name}: $s")
}
override fun apply(project: Project, context: KobaltContext) { override fun apply(project: Project, context: KobaltContext) {
super.apply(project, context) super.apply(project, context)
// cleanUpActors() // cleanUpActors()
@ -66,7 +76,7 @@ open class JvmCompilerPlugin @Inject constructor(
// users don't have to specify a test{} // users don't have to specify a test{}
// //
if (project.testConfigs.isEmpty()) { if (project.testConfigs.isEmpty()) {
project.testConfigs.add(TestConfig(project, isDefault = true)) project.testConfigs.add(TestConfig(project))
} }
project.testConfigs.forEach { config -> project.testConfigs.forEach { config ->
val taskName = if (config.name.isEmpty()) TASK_TEST else TASK_TEST + config.name val taskName = if (config.name.isEmpty()) TASK_TEST else TASK_TEST + config.name
@ -79,28 +89,20 @@ open class JvmCompilerPlugin @Inject constructor(
} }
private fun taskTest(project: Project, configName: String): TaskResult { private fun taskTest(project: Project, configName: String): TaskResult {
context.logger.log(project.name, 2, "Running tests: $configName") lp(project, "Running tests: $configName")
val testContributor = ActorUtils.selectAffinityActor(project, context, val runContributor = ActorUtils.selectAffinityActor(project, context,
context.pluginInfo.testRunnerContributors) context.pluginInfo.testRunnerContributors)
if (testContributor != null && testContributor.affinity(project, context) > 0) { if (runContributor != null && runContributor.affinity(project, context) > 0) {
// val td1 = dependencyManager.testDependencies(project, context) return runContributor.run(project, context, configName, dependencyManager.testDependencies(project,
val testDependencies = dependencyManager.calculateDependencies(project, context, context))
dependencyFilter = dependencyManager.createDependencyFilter(project, project.testDependencies),
scopes = listOf(Scope.TEST))
val compileDependencies = dependencyManager.calculateDependencies(project, context,
scopes = listOf(Scope.COMPILE, Scope.COMPILEONLY))
val allDependencies = (testDependencies + compileDependencies).distinct()
return testContributor.run(project, context, configName, allDependencies.toList())
} else { } else {
context.logger.log(project.name, 2, log(1, "Couldn't find a test runner for project ${project.name}, did you specify a dependenciesTest{}?")
"Couldn't find a test runner for project ${project.name}, did you specify dependenciesTest{}?")
return TaskResult() return TaskResult()
} }
} }
@Task(name = TASK_CLEAN, description = "Clean the project", group = GROUP_BUILD, @Task(name = TASK_CLEAN, description = "Clean the project", group = GROUP_BUILD)
runBefore = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
fun taskClean(project: Project): TaskResult { fun taskClean(project: Project): TaskResult {
java.io.File(project.directory, project.buildDirectory).let { dir -> java.io.File(project.directory, project.buildDirectory).let { dir ->
if (!dir.deleteRecursively()) { if (!dir.deleteRecursively()) {
@ -110,6 +112,37 @@ open class JvmCompilerPlugin @Inject constructor(
return TaskResult() return TaskResult()
} }
/**
* Copy the resources from a source directory to the build one
*/
protected fun copyResources(project: Project, sourceSet: SourceSet) {
var outputDir = sourceSet.outputDir
val variantSourceDirs = context.variant.resourceDirectories(project, sourceSet)
if (variantSourceDirs.size > 0) {
lp(project, "Copying $sourceSet resources")
val absOutputDir = File(KFiles.joinDir(project.directory, project.buildDirectory, outputDir))
variantSourceDirs.map { File(project.directory, it.path) }.filter {
it.exists()
}.forEach {
log(2, "Copying from $it to $absOutputDir")
KFiles.copyRecursively(it, absOutputDir, deleteFirst = false)
}
} else {
lp(project, "No resources to copy for $sourceSet")
}
}
protected fun compilerArgsFor(project: Project): List<String> {
val result = project.projectProperties.get(COMPILER_ARGS)
if (result != null) {
@Suppress("UNCHECKED_CAST")
return result as List<String>
} else {
return emptyList()
}
}
@IncrementalTask(name = TASK_COMPILE_TEST, description = "Compile the tests", group = GROUP_BUILD, @IncrementalTask(name = TASK_COMPILE_TEST, description = "Compile the tests", group = GROUP_BUILD,
dependsOn = arrayOf(TASK_COMPILE)) dependsOn = arrayOf(TASK_COMPILE))
fun taskCompileTest(project: Project): IncrementalTaskInfo { fun taskCompileTest(project: Project): IncrementalTaskInfo {
@ -125,8 +158,8 @@ open class JvmCompilerPlugin @Inject constructor(
) )
} }
private fun sourceDirectories(project: Project, context: KobaltContext, isTest: Boolean) private fun sourceDirectories(project: Project, context: KobaltContext)
= context.variant.sourceDirectories(project, context, SourceSet.of(isTest)) = context.variant.sourceDirectories(project, context, SourceSet.of(isTest = false))
@IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project", group = GROUP_BUILD, @IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project", group = GROUP_BUILD,
runAfter = arrayOf(TASK_CLEAN)) runAfter = arrayOf(TASK_CLEAN))
@ -151,65 +184,44 @@ open class JvmCompilerPlugin @Inject constructor(
val results = arrayListOf<TaskResult>() val results = arrayListOf<TaskResult>()
val compilerContributors = context.pluginInfo.compilerContributors val compilerContributors = context.pluginInfo.compilerContributors
ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors) ActorUtils.selectAffinityActors(project, context,
context.pluginInfo.compilerContributors)
var failedResult: TaskResult? = null var failedResult: TaskResult? = null
if (compilerContributors.isEmpty()) { if (compilerContributors.isEmpty()) {
throw KobaltException("Couldn't find any compiler for project ${project.name}") throw KobaltException("Couldn't find any compiler for project ${project.name}")
} else { } else {
// Generate BuildConfig if applicable
context.variant.maybeGenerateBuildConfig(project, context)
val allCompilers = compilerContributors.flatMap { it.compilersFor(project, context)}.sorted() val allCompilers = compilerContributors.flatMap { it.compilersFor(project, context)}.sorted()
allCompilers.forEach { compiler ->
/** val contributedSourceDirs =
* Swap the Java and Kotlin compilers from the list. if (isTest) {
*/ context.testSourceDirectories(project)
fun swapJavaAndKotlin(allCompilers: List<ICompilerDescription>): List<ICompilerDescription> { } else {
val result = ArrayList(allCompilers) context.sourceDirectories(project)
var ik = -1
var ij = -1
allCompilers.withIndex().forEach { wi ->
if (wi.value.sourceSuffixes.contains("java")) ij = wi.index
if (wi.value.sourceSuffixes.contains("kt")) ik = wi.index
}
if (ik >= 0 && ij >= 0) {
Collections.swap(result, ik, ij)
}
return result
}
// If this project has a kapt{} directive, we want to run the Java compiler first
val hasKapt = project.projectProperties.get("kaptConfig") != null
val allCompilersSorted = if (hasKapt) swapJavaAndKotlin(allCompilers) else allCompilers
var done = false
// The directory where the classes get compiled
val buildDirectory =
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,
sourceDirectories(project, context, isTest), isTest, buildDirectory)
results.addAll(compilerResults.successResults)
if (failedResult == null) failedResult = compilerResults.failedResult
compilerResults.failedResult?.let { failedResult ->
done = true
failedResult.errorMessage?.let { errorMessage ->
error(text = errorMessage)
} }
val sourceFiles = KFiles.findSourceFiles(project.directory,
contributedSourceDirs.map { it.path }, compiler.sourceSuffixes)
if (sourceFiles.size > 0) {
// TODO: createCompilerActionInfo recalculates the source files, only compute them
// once and pass them
val info = createCompilerActionInfo(project, context, compiler, isTest,
sourceDirectories(project, context), sourceSuffixes = compiler.sourceSuffixes)
val thisResult = compiler.compile(project, context, info)
results.add(thisResult)
if (!thisResult.success && failedResult == null) {
failedResult = thisResult
}
} else {
log(2, "Compiler $compiler not running on ${project.name} since no source files were found")
} }
} }
return if (failedResult != null) failedResult!! return if (failedResult != null) failedResult!!
else if (results.size > 0) results[0] else if (results.size > 0) results[0]
else TaskResult(true) else TaskResult(true)
} }
} }
private val allProjects = arrayListOf<ProjectDescription>() val allProjects = arrayListOf<ProjectDescription>()
// IProjectContributor // IProjectContributor
override fun projects() = allProjects override fun projects() = allProjects
@ -219,27 +231,27 @@ open class JvmCompilerPlugin @Inject constructor(
} }
fun addDependentProjects(project: Project, dependents: List<Project>) { fun addDependentProjects(project: Project, dependents: List<Project>) {
project.dependsOn.addAll(dependents) project.projectExtra.dependsOn.addAll(dependents)
with(ProjectDescription(project, dependents)) { with(ProjectDescription(project, dependents)) {
allProjects.add(this) allProjects.add(this)
} }
project.projectProperties.put(DEPENDENT_PROJECTS, allProjects)
} }
@Task(name = "doc", description = "Generate the documentation for the project", group = GROUP_DOCUMENTATION, @Task(name = "doc", description = "Generate the documentation for the project", group = GROUP_DOCUMENTATION)
runBefore = arrayOf("assemble"), runAfter = arrayOf("clean"))
fun taskJavadoc(project: Project): TaskResult { fun taskJavadoc(project: Project): TaskResult {
val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors) val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors)
if (docGenerator != null) { if (docGenerator != null) {
val buildDirectory = File(project.buildDirectory, JvmCompilerPlugin.DOCS_DIRECTORY)
val contributors = val contributors =
ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors) ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors)
var result: TaskResult? = null var result: TaskResult? = null
contributors.forEach { contributors.forEach {
it.compilersFor(project, context).forEach { compiler -> it.compilersFor(project, context).forEach { compiler ->
result = docGenerator.generateDoc(project, context, result = docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context,
compilerUtils.createCompilerActionInfo(project, context, compiler, compiler,
isTest = false, sourceDirectories = sourceDirectories(project, context, false), isTest = false, sourceDirectories = sourceDirectories(project, context),
sourceSuffixes = compiler.sourceSuffixes, buildDirectory = buildDirectory)) sourceSuffixes = compiler.sourceSuffixes))
} }
} }
return result!! return result!!
@ -249,10 +261,107 @@ open class JvmCompilerPlugin @Inject constructor(
} }
} }
/**
* Naïve implementation: just exclude all dependencies that start with one of the excluded dependencies.
* Should probably make exclusion more generic (full on string) or allow exclusion to be specified
* formally by groupId or artifactId.
*/
private fun isDependencyExcluded(id: IClasspathDependency, excluded: List<IClasspathDependency>)
= excluded.any { id.id.startsWith(it.id) }
/**
* Create a CompilerActionInfo (all the information that a compiler needs to know) for the given parameters.
* Runs all the contributors and interceptors relevant to that task.
*/
protected fun createCompilerActionInfo(project: Project, context: KobaltContext, compiler: ICompiler,
isTest: Boolean, sourceDirectories: List<File>, sourceSuffixes: List<String>): CompilerActionInfo {
copyResources(project, SourceSet.of(isTest))
val fullClasspath = if (isTest) dependencyManager.testDependencies(project, context)
else dependencyManager.dependencies(project, context)
// Remove all the excluded dependencies from the classpath
val classpath = fullClasspath.filter {
! isDependencyExcluded(it, project.excludedDependencies)
}
val buildDirectory = if (isTest) File(project.buildDirectory, KFiles.TEST_CLASSES_DIR)
else File(project.classesDir(context))
buildDirectory.mkdirs()
val initialSourceDirectories = ArrayList<File>(sourceDirectories)
// Source directories from the contributors
val contributedSourceDirs =
if (isTest) {
context.pluginInfo.testSourceDirContributors.flatMap { it.testSourceDirectoriesFor(project, context) }
} else {
context.pluginInfo.sourceDirContributors.flatMap { it.sourceDirectoriesFor(project, context) }
}
initialSourceDirectories.addAll(contributedSourceDirs)
// Transform them with the interceptors, if any
val allSourceDirectories =
if (isTest) {
initialSourceDirectories
} else {
context.pluginInfo.sourceDirectoriesInterceptors.fold(initialSourceDirectories.toList(),
{ sd, interceptor -> interceptor.intercept(project, context, sd) })
}.filter {
File(project.directory, it.path).exists()
}.filter {
! KFiles.isResource(it.path)
}.distinct()
// Now that we have all the source directories, find all the source files in them
val projectDirectory = File(project.directory)
val sourceFiles = if (compiler.canCompileDirectories) {
allSourceDirectories.map { File(projectDirectory, it.path).path }
} else {
files.findRecursively(projectDirectory, allSourceDirectories,
{ file -> sourceSuffixes.any { file.endsWith(it) } })
.map { File(projectDirectory, it).path }
}
// Special treatment if we are compiling Kotlin files and the project also has a java source
// directory. In this case, also pass that java source directory to the Kotlin compiler as is
// so that it can parse its symbols
// Note: this should actually be queried on the compiler object so that this method, which
// is compiler agnostic, doesn't hardcode Kotlin specific stuff
val extraSourceFiles = arrayListOf<String>()
if (sourceSuffixes.any { it.contains("kt")}) {
project.sourceDirectories.forEach {
val javaDir = KFiles.joinDir(project.directory, it)
if (File(javaDir).exists()) {
if (it.contains("java")) {
extraSourceFiles.add(javaDir)
// Add all the source directories contributed as potential Java directories too
// (except our own)
context.pluginInfo.sourceDirContributors.filter { it != this }.forEach {
extraSourceFiles.addAll(it.sourceDirectoriesFor(project, context).map { it.path })
}
}
}
}
}
val allSources = (sourceFiles + extraSourceFiles).distinct().filter { File(it).exists() }
// Finally, alter the info with the compiler interceptors before returning it
val initialActionInfo = CompilerActionInfo(projectDirectory.path, classpath, allSources,
sourceSuffixes, buildDirectory, emptyList() /* the flags will be provided by flag contributors */)
val result = context.pluginInfo.compilerInterceptors.fold(initialActionInfo, { ai, interceptor ->
interceptor.intercept(project, context, ai)
})
return result
}
// ISourceDirectoryContributor // ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext) override fun sourceDirectoriesFor(project: Project, context: KobaltContext)
= if (accept(project)) { = if (accept(project)) {
sourceDirectories(project, context, isTest = false) sourceDirectories(project, context)
} else { } else {
arrayListOf() arrayListOf()
} }

View file

@ -2,7 +2,7 @@ package com.beust.kobalt.internal
import com.beust.kobalt.KobaltException import com.beust.kobalt.KobaltException
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream
import javax.xml.bind.JAXBContext import javax.xml.bind.JAXBContext
@ -72,13 +72,13 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
val plugins = arrayListOf<IPlugin>() val plugins = arrayListOf<IPlugin>()
val projectContributors = arrayListOf<IProjectContributor>() val projectContributors = arrayListOf<IProjectContributor>()
val classpathContributors = arrayListOf<IClasspathContributor>() val classpathContributors = arrayListOf<IClasspathContributor>()
val templateContributors = arrayListOf<ITemplateContributor>() val initContributors = arrayListOf<ITemplateContributor>()
val repoContributors = arrayListOf<IRepoContributor>() val repoContributors = arrayListOf<IRepoContributor>()
val compilerFlagContributors = arrayListOf<ICompilerFlagContributor>() val compilerFlagContributors = arrayListOf<ICompilerFlagContributor>()
val compilerInterceptors = arrayListOf<ICompilerInterceptor>() val compilerInterceptors = arrayListOf<ICompilerInterceptor>()
val sourceDirectoriesInterceptors = arrayListOf<ISourceDirectoryInterceptor>() val sourceDirectoriesInterceptors = arrayListOf<ISourceDirectoryInterceptor>()
val buildDirectoryInterceptors = arrayListOf<IBuildDirectoryInterceptor>() val buildDirectoryInterceptors = arrayListOf<IBuildDirectoryInterceptor>()
// val runnerContributors = arrayListOf<IRunnerContributor>() val runnerContributors = arrayListOf<IRunnerContributor>()
val testRunnerContributors = arrayListOf<ITestRunnerContributor>() val testRunnerContributors = arrayListOf<ITestRunnerContributor>()
val classpathInterceptors = arrayListOf<IClasspathInterceptor>() val classpathInterceptors = arrayListOf<IClasspathInterceptor>()
val compilerContributors = arrayListOf<ICompilerContributor>() val compilerContributors = arrayListOf<ICompilerContributor>()
@ -89,16 +89,10 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
val taskContributors = arrayListOf<ITaskContributor>() val taskContributors = arrayListOf<ITaskContributor>()
val assemblyContributors = arrayListOf<IAssemblyContributor>() val assemblyContributors = arrayListOf<IAssemblyContributor>()
val incrementalAssemblyContributors = arrayListOf<IIncrementalAssemblyContributor>() val incrementalAssemblyContributors = arrayListOf<IIncrementalAssemblyContributor>()
val incrementalTaskContributors = arrayListOf<IIncrementalTaskContributor>()
// Not documented yet // Not documented yet
val buildConfigContributors = arrayListOf<IBuildConfigContributor>() val buildConfigContributors = arrayListOf<IBuildConfigContributor>()
val mavenIdInterceptors = arrayListOf<IMavenIdInterceptor>() val mavenIdInterceptors = arrayListOf<IMavenIdInterceptor>()
val jvmFlagContributors = arrayListOf<IJvmFlagContributor>()
val localMavenRepoPathInterceptors = arrayListOf<ILocalMavenRepoPathInterceptor>()
val buildListeners = arrayListOf<IBuildListener>()
val buildReportContributors = arrayListOf<IBuildReportContributor>()
val docFlagContributors = arrayListOf<IDocFlagContributor>()
// Note: intentionally repeating them here even though they are defined by our base class so // Note: intentionally repeating them here even though they are defined by our base class so
// that this class always contains the full list of contributors and interceptors // that this class always contains the full list of contributors and interceptors
@ -124,7 +118,7 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
fun readKobaltPluginXml(): PluginInfo { fun readKobaltPluginXml(): PluginInfo {
// Note: use forward slash here since we're looking up this file in a .jar file // Note: use forward slash here since we're looking up this file in a .jar file
val url = Kobalt::class.java.classLoader.getResource(PLUGIN_CORE_XML) val url = Kobalt::class.java.classLoader.getResource(PLUGIN_CORE_XML)
kobaltLog(2, "URL for core kobalt-plugin.xml: $url") log(2, "URL for core kobalt-plugin.xml: $url")
if (url != null) { if (url != null) {
return readPluginXml(url.openConnection().inputStream) return readPluginXml(url.openConnection().inputStream)
} else { } else {
@ -140,7 +134,7 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java) val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java)
val kobaltPlugin: KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(ins) val kobaltPlugin: KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(ins)
as KobaltPluginXml as KobaltPluginXml
kobaltLog(2, "Parsed plugin XML file, found: " + kobaltPlugin.name) log(2, "Parsed plugin XML file, found: " + kobaltPlugin.name)
val result = val result =
try { try {
PluginInfo(kobaltPlugin, pluginClassLoader, classLoader) PluginInfo(kobaltPlugin, pluginClassLoader, classLoader)
@ -162,21 +156,10 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
GuiceFactory() GuiceFactory()
} }
fun forName(className: String) : Class<*> { fun forName(className: String) =
fun loadClass(className: String, classLoader: ClassLoader?) : Class<*>? { if (pluginClassLoader != null) pluginClassLoader.loadClass(className)
try { else if (classLoader != null) classLoader.loadClass(className)
return classLoader?.loadClass(className) else Class.forName(className)
} catch(ex: ClassNotFoundException) {
return null
}
}
val result = loadClass(className, classLoader)
?: loadClass(className, pluginClassLoader)
?: Class.forName(className)
return result
}
// //
// Populate pluginInfo with what was found in Kobalt's own kobalt-plugin.xml // Populate pluginInfo with what was found in Kobalt's own kobalt-plugin.xml
@ -193,11 +176,11 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
if (this is ICompilerFlagContributor) compilerFlagContributors.add(this) if (this is ICompilerFlagContributor) compilerFlagContributors.add(this)
if (this is ICompilerInterceptor) compilerInterceptors.add(this) if (this is ICompilerInterceptor) compilerInterceptors.add(this)
if (this is IDocContributor) docContributors.add(this) if (this is IDocContributor) docContributors.add(this)
if (this is ITemplateContributor) templateContributors.add(this) if (this is ITemplateContributor) initContributors.add(this)
if (this is IPlugin) plugins.add(this) if (this is IPlugin) plugins.add(this)
if (this is IProjectContributor) projectContributors.add(this) if (this is IProjectContributor) projectContributors.add(this)
if (this is IRepoContributor) repoContributors.add(this) if (this is IRepoContributor) repoContributors.add(this)
// if (this is IRunnerContributor) runnerContributors.add(this) if (this is IRunnerContributor) runnerContributors.add(this)
if (this is ISourceDirectoryContributor) sourceDirContributors.add(this) if (this is ISourceDirectoryContributor) sourceDirContributors.add(this)
if (this is ISourceDirectoryInterceptor) sourceDirectoriesInterceptors.add(this) if (this is ISourceDirectoryInterceptor) sourceDirectoriesInterceptors.add(this)
if (this is ITaskContributor) taskContributors.add(this) if (this is ITaskContributor) taskContributors.add(this)
@ -207,33 +190,27 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
if (this is IBuildConfigContributor) buildConfigContributors.add(this) if (this is IBuildConfigContributor) buildConfigContributors.add(this)
if (this is IAssemblyContributor) assemblyContributors.add(this) if (this is IAssemblyContributor) assemblyContributors.add(this)
if (this is IIncrementalAssemblyContributor) incrementalAssemblyContributors.add(this) if (this is IIncrementalAssemblyContributor) incrementalAssemblyContributors.add(this)
if (this is IIncrementalTaskContributor) incrementalTaskContributors.add(this)
// Not documented yet // Not documented yet
if (this is ITestJvmFlagContributor) testJvmFlagContributors.add(this) if (this is ITestJvmFlagContributor) testJvmFlagContributors.add(this)
if (this is ITestJvmFlagInterceptor) testJvmFlagInterceptors.add(this) if (this is ITestJvmFlagInterceptor) testJvmFlagInterceptors.add(this)
if (this is IJvmFlagContributor) jvmFlagContributors.add(this)
if (this is ILocalMavenRepoPathInterceptor) localMavenRepoPathInterceptors.add(this)
if (this is IBuildListener) buildListeners.add(this)
if (this is IBuildReportContributor) buildReportContributors.add(this)
if (this is IDocFlagContributor) docFlagContributors.add(this)
} }
} }
} }
fun cleanUp() { fun cleanUp() {
listOf(projectContributors, classpathContributors, templateContributors, listOf(projectContributors, classpathContributors, initContributors,
repoContributors, compilerFlagContributors, compilerInterceptors, repoContributors, compilerFlagContributors, compilerInterceptors,
sourceDirectoriesInterceptors, buildDirectoryInterceptors, sourceDirectoriesInterceptors, buildDirectoryInterceptors,
/* runnerContributors, */ testRunnerContributors, classpathInterceptors, runnerContributors, testRunnerContributors, classpathInterceptors,
compilerContributors, docContributors, sourceDirContributors, compilerContributors, docContributors, sourceDirContributors,
testSourceDirContributors, buildConfigFieldContributors, testSourceDirContributors, buildConfigFieldContributors,
taskContributors, incrementalTaskContributors, assemblyContributors, taskContributors, assemblyContributors,
incrementalAssemblyContributors, testJvmFlagInterceptors, incrementalAssemblyContributors, testJvmFlagInterceptors
jvmFlagContributors, localMavenRepoPathInterceptors, buildListeners,
buildReportContributors, docFlagContributors
).forEach { ).forEach {
it.forEach(IPluginActor::cleanUpActors) it.forEach {
it.cleanUpActors()
}
} }
} }
@ -241,18 +218,18 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
* Add the content of @param[pluginInfo] to this pluginInfo. * Add the content of @param[pluginInfo] to this pluginInfo.
*/ */
fun addPluginInfo(pluginInfo: PluginInfo) { fun addPluginInfo(pluginInfo: PluginInfo) {
kobaltLog(2, "Found new plug-in, adding it to pluginInfo: $pluginInfo") log(2, "Found new plug-in, adding it to pluginInfo: $pluginInfo")
plugins.addAll(pluginInfo.plugins) plugins.addAll(pluginInfo.plugins)
classpathContributors.addAll(pluginInfo.classpathContributors) classpathContributors.addAll(pluginInfo.classpathContributors)
projectContributors.addAll(pluginInfo.projectContributors) projectContributors.addAll(pluginInfo.projectContributors)
templateContributors.addAll(pluginInfo.templateContributors) initContributors.addAll(pluginInfo.initContributors)
repoContributors.addAll(pluginInfo.repoContributors) repoContributors.addAll(pluginInfo.repoContributors)
compilerFlagContributors.addAll(pluginInfo.compilerFlagContributors) compilerFlagContributors.addAll(pluginInfo.compilerFlagContributors)
compilerInterceptors.addAll(pluginInfo.compilerInterceptors) compilerInterceptors.addAll(pluginInfo.compilerInterceptors)
sourceDirectoriesInterceptors.addAll(pluginInfo.sourceDirectoriesInterceptors) sourceDirectoriesInterceptors.addAll(pluginInfo.sourceDirectoriesInterceptors)
buildDirectoryInterceptors.addAll(pluginInfo.buildDirectoryInterceptors) buildDirectoryInterceptors.addAll(pluginInfo.buildDirectoryInterceptors)
// runnerContributors.addAll(pluginInfo.runnerContributors) runnerContributors.addAll(pluginInfo.runnerContributors)
testRunnerContributors.addAll(pluginInfo.testRunnerContributors) testRunnerContributors.addAll(pluginInfo.testRunnerContributors)
classpathInterceptors.addAll(pluginInfo.classpathInterceptors) classpathInterceptors.addAll(pluginInfo.classpathInterceptors)
compilerContributors.addAll(pluginInfo.compilerContributors) compilerContributors.addAll(pluginInfo.compilerContributors)
@ -260,7 +237,6 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
sourceDirContributors.addAll(pluginInfo.sourceDirContributors) sourceDirContributors.addAll(pluginInfo.sourceDirContributors)
buildConfigFieldContributors.addAll(pluginInfo.buildConfigFieldContributors) buildConfigFieldContributors.addAll(pluginInfo.buildConfigFieldContributors)
taskContributors.addAll(pluginInfo.taskContributors) taskContributors.addAll(pluginInfo.taskContributors)
incrementalTaskContributors.addAll(pluginInfo.incrementalTaskContributors)
testSourceDirContributors.addAll(pluginInfo.testSourceDirContributors) testSourceDirContributors.addAll(pluginInfo.testSourceDirContributors)
mavenIdInterceptors.addAll(pluginInfo.mavenIdInterceptors) mavenIdInterceptors.addAll(pluginInfo.mavenIdInterceptors)
buildConfigContributors.addAll(pluginInfo.buildConfigContributors) buildConfigContributors.addAll(pluginInfo.buildConfigContributors)
@ -268,11 +244,6 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
incrementalAssemblyContributors.addAll(pluginInfo.incrementalAssemblyContributors) incrementalAssemblyContributors.addAll(pluginInfo.incrementalAssemblyContributors)
testJvmFlagContributors.addAll(pluginInfo.testJvmFlagContributors) testJvmFlagContributors.addAll(pluginInfo.testJvmFlagContributors)
testJvmFlagInterceptors.addAll(pluginInfo.testJvmFlagInterceptors) testJvmFlagInterceptors.addAll(pluginInfo.testJvmFlagInterceptors)
jvmFlagContributors.addAll(pluginInfo.jvmFlagContributors)
localMavenRepoPathInterceptors.addAll(pluginInfo.localMavenRepoPathInterceptors)
buildListeners.addAll(pluginInfo.buildListeners)
buildReportContributors.addAll(pluginInfo.buildReportContributors)
docFlagContributors.addAll(pluginInfo.docFlagContributors)
} }
} }

View file

@ -1,11 +1,9 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.BUILD_SCRIPT_CONFIG
import com.beust.kobalt.Constants
import com.beust.kobalt.ProxyConfig import com.beust.kobalt.ProxyConfig
import com.beust.kobalt.homeDir import com.beust.kobalt.homeDir
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.log
import com.google.inject.Inject import com.google.inject.Inject
import com.google.inject.Singleton import com.google.inject.Singleton
import java.io.File import java.io.File
@ -17,39 +15,22 @@ import javax.xml.bind.annotation.XmlRootElement
/** /**
* The root element of kobalt-settings.xml * The root element of kobalt-settings.xml
*/ */
@XmlRootElement(name = "kobaltSettings") @XmlRootElement(name = "kobalt-settings")
class KobaltSettingsXml { class KobaltSettingsXml {
@XmlElement(name = "localCache") @JvmField @XmlElement(name = "local-repo") @JvmField
var localCache: String = homeDir(KFiles.KOBALT_DOT_DIR, "cache") var localRepo: String = homeDir(KFiles.KOBALT_DOT_DIR, "repository")
@XmlElement(name = "localMavenRepo") @JvmField @XmlElement(name = "default-repos") @JvmField
var localMavenRepo: String = homeDir(KFiles.KOBALT_DOT_DIR, "localMavenRepo")
@XmlElement(name = "defaultRepos") @JvmField
var defaultRepos: DefaultReposXml? = null var defaultRepos: DefaultReposXml? = null
@XmlElement(name = "proxies") @JvmField @XmlElement(name = "proxy") @JvmField
var proxies: ProxiesXml? = null var proxy: ProxyXml? = null
@XmlElement(name = "kobaltCompilerVersion") @JvmField @XmlElement(name = "kobalt-compiler-version") @JvmField
var kobaltCompilerVersion: String = Constants.KOTLIN_COMPILER_VERSION var kobaltCompilerVersion: String = "1.0.2"
@XmlElement(name = "kobaltCompilerRepo") @JvmField @XmlElement(name = "kobalt-compiler-repo") @JvmField
var kobaltCompilerRepo: String? = null var kobaltCompilerRepo: String? = null
@XmlElement(name = "kobaltCompilerFlags") @JvmField
var kobaltCompilerFlags: String? = null
@XmlElement(name = "kobaltCompilerSeparateProcess") @JvmField
var kobaltCompilerSeparateProcess: Boolean = false
@XmlElement(name = "autoUpdate") @JvmField
var autoUpdate: Boolean = false
}
class ProxiesXml {
@XmlElement @JvmField
var proxy: List<ProxyXml> = arrayListOf()
} }
class ProxyXml { class ProxyXml {
@ -61,9 +42,6 @@ class ProxyXml {
@XmlElement @JvmField @XmlElement @JvmField
var type: String = "" var type: String = ""
@XmlElement @JvmField
var nonProxyHosts: String = ""
} }
class DefaultReposXml { class DefaultReposXml {
@ -71,37 +49,19 @@ class DefaultReposXml {
var repo: List<String> = arrayListOf() var repo: List<String> = arrayListOf()
} }
fun List<ProxyConfig>.getProxy(protocol:String) = find { it.type==protocol }
/** /**
* The object Kobalt refers to for settings. * The object Kobalt refers to for settings.
*/ */
@Singleton @Singleton
class KobaltSettings @Inject constructor(val xmlFile: KobaltSettingsXml) { class KobaltSettings @Inject constructor(val xmlFile: KobaltSettingsXml) {
/** /**
* Location of the cache repository. * Location of the local repo.
*/ */
var localCache = KFiles.makeDir(xmlFile.localCache) // var for testing var localRepo = KFiles.makeDir(xmlFile.localRepo) // var for testing
/**
* Location of the local Maven repo for the task "publishToLocalMaven".
*/
val localMavenRepo = KFiles.makeDir(xmlFile.localMavenRepo)
/**
* If true, Kobalt will automatically update itself if a new version is found.
*/
val autoUpdate = xmlFile.autoUpdate
/**
* If true, the Kotlin compiler will always be launched in a separate JVM, even if the requested
* version is the same as the internal version.
*/
val kobaltCompilerSeparateProcess = xmlFile.kobaltCompilerSeparateProcess
val defaultRepos = xmlFile.defaultRepos?.repo val defaultRepos = xmlFile.defaultRepos?.repo
val proxyConfigs = with(xmlFile.proxies?.proxy) { val proxyConfig = with(xmlFile.proxy) {
fun toIntOr(s: String, defaultValue: Int) = try { //TODO can be extracted to some global Utils fun toIntOr(s: String, defaultValue: Int) = try { //TODO can be extracted to some global Utils
s.toInt() s.toInt()
} catch(e: NumberFormatException) { } catch(e: NumberFormatException) {
@ -109,40 +69,12 @@ class KobaltSettings @Inject constructor(val xmlFile: KobaltSettingsXml) {
} }
if (this != null) { if (this != null) {
map { proxyXml-> ProxyConfig(host, toIntOr(port, 0), type)
ProxyConfig(proxyXml.host, toIntOr(proxyXml.port, 0), proxyXml.type, proxyXml.nonProxyHosts) } else null
}
} else {
null
}
} }
val kobaltCompilerVersion : String? var kobaltCompilerVersion = xmlFile.kobaltCompilerVersion
get() { var kobaltCompilerRepo = xmlFile.kobaltCompilerRepo
return if (BUILD_SCRIPT_CONFIG != null && BUILD_SCRIPT_CONFIG?.kobaltCompilerVersion != null) {
BUILD_SCRIPT_CONFIG?.kobaltCompilerVersion
} else {
xmlFile.kobaltCompilerVersion
}
}
val kobaltCompilerRepo : String?
get() {
return if (BUILD_SCRIPT_CONFIG != null && BUILD_SCRIPT_CONFIG?.kobaltCompilerRepo != null) {
BUILD_SCRIPT_CONFIG?.kobaltCompilerRepo
} else {
xmlFile.kobaltCompilerRepo
}
}
val kobaltCompilerFlags : String?
get() {
return if (BUILD_SCRIPT_CONFIG != null && BUILD_SCRIPT_CONFIG?.kobaltCompilerFlags != null) {
BUILD_SCRIPT_CONFIG?.kobaltCompilerFlags
} else {
xmlFile.kobaltCompilerFlags
}
}
companion object { companion object {
val SETTINGS_FILE_PATH = KFiles.joinDir(KFiles.HOME_KOBALT_DIR.absolutePath, "settings.xml") val SETTINGS_FILE_PATH = KFiles.joinDir(KFiles.HOME_KOBALT_DIR.absolutePath, "settings.xml")
@ -158,7 +90,7 @@ class KobaltSettings @Inject constructor(val xmlFile: KobaltSettingsXml) {
return result return result
} }
} else { } else {
kobaltLog(2, "Couldn't find ${KobaltSettings.SETTINGS_FILE_PATH}, using default settings") log(2, "Couldn't find ${KobaltSettings.SETTINGS_FILE_PATH}, using default settings")
return KobaltSettings(KobaltSettingsXml()) return KobaltSettings(KobaltSettingsXml())
} }
} }

View file

@ -1,20 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.maven.DependencyManager
import com.google.inject.Inject
import java.io.File
/**
* The jar files that Kotlin needs to run.
*/
class KotlinJarFiles @Inject constructor(val dependencyManager: DependencyManager,
val settings: KobaltSettings){
private fun getKotlinCompilerJar(name: String): File {
val id = "org.jetbrains.kotlin:kotlin-$name:${settings.kobaltCompilerVersion}"
val dep = dependencyManager.create(id)
return dep.jarFile.get().absoluteFile
}
val stdlib: File get() = getKotlinCompilerJar("stdlib")
val compiler: File get() = getKotlinCompilerJar("compiler-embeddable")
}

View file

@ -1,21 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
/**
* KotlinTestRunner triggers if it finds a dependency on io.kotlintest but other than that, it just
* uses the regular JUnitRunner.
*/
class KotlinTestRunner : JUnitRunner() {
override val dependencyName = "io.kotlintest"
override val runnerName = "Kotlin Test"
/**
* KotlinTestRunner runs tests in the init{} initializer, so ignore all the extra
* classes generated by the Kotlin compiler.
*/
override fun filterTestClasses(projet: Project, context: KobaltContext, classes: List<String>)
= classes.filter { !it.contains("$") }
}

View file

@ -1,130 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.Args
import com.beust.kobalt.KobaltException
import com.beust.kobalt.misc.*
import com.google.inject.Inject
import com.google.inject.Singleton
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
interface ILogger {
fun log(tag: CharSequence, level: Int, message: CharSequence, newLine: Boolean = true)
}
/**
* This class manages logs for parallel builds. These logs come from multiple projects interwoven as
* they are being scheduled on different threads. This class maintains a "current" project which has
* its logs always displayed instantaneously while logs from other projects are being stored for later display.
* Once the current project is done, this class will catch up all the finished project logs and then
* pick the next current project to be displayed live.
*
* Yes, this code was pretty painful to write and I'm pretty sure it can be made less ugly.
*/
@Singleton
class ParallelLogger @Inject constructor(val args: Args) : ILogger {
enum class Type { LOG, WARN, ERROR }
class LogLine(val name: CharSequence? = null, val level: Int, val message: CharSequence, val type: Type,
val newLine: Boolean)
private val logLines = ConcurrentHashMap<CharSequence, ArrayList<LogLine>>()
private val runningProjects = ConcurrentLinkedQueue<String>()
var startTime: Long? = null
fun onProjectStarted(name: String) {
if (startTime == null) {
startTime = System.currentTimeMillis()
}
runningProjects.add(name)
logLines[name] = arrayListOf()
if (currentName == null) {
currentName = name
}
}
val stoppedProjects = ConcurrentHashMap<String, String>()
fun onProjectStopped(name: String) {
debug("onProjectStopped($name)")
stoppedProjects[name] = name
if (name == currentName && runningProjects.any()) {
emptyProjectLog(name)
var nextProject = runningProjects.peek()
while (nextProject != null && stoppedProjects.containsKey(nextProject)) {
val sp = runningProjects.remove()
emptyProjectLog(sp)
nextProject = runningProjects.peek()
}
currentName = nextProject
} else {
debug("Non current project $name stopping, not doing anything")
}
}
private fun debug(s: CharSequence) {
if (args.log >= 3) {
val time = System.currentTimeMillis() - startTime!!
kobaltLog(1, " ### [$time] $s")
}
}
val LOCK = Any()
var currentName: String? = null
set(newName) {
field = newName
}
private fun displayLine(ll: LogLine) {
val time = System.currentTimeMillis() - startTime!!
val m = (if (args.dev) "### [$time] " else "") + ll.message
when(ll.type) {
Type.LOG -> kobaltLog(ll.level, m, ll.newLine)
Type.WARN -> kobaltWarn(m)
Type.ERROR -> kobaltError(m)
}
}
private fun emptyProjectLog(name: CharSequence?) {
val lines = logLines[name]
if (lines != null && lines.any()) {
debug("emptyProjectLog($name)")
lines.forEach {
displayLine(it)
}
lines.clear()
debug("Done emptyProjectLog($name)")
// logLines.remove(name)
} else if (lines == null) {
throw KobaltException("Didn't call onStartProject() for $name")
}
}
private fun addLogLine(name: CharSequence, ll: LogLine) {
if (name != currentName) {
val list = logLines[name] ?: arrayListOf()
logLines[name] = list
list.add(ll)
} else {
emptyProjectLog(name)
displayLine(ll)
}
}
override fun log(tag: CharSequence, level: Int, message: CharSequence, newLine: Boolean) {
if (args.sequential) {
kobaltLog(level, message, newLine)
} else {
addLogLine(tag, LogLine(tag, level, message, Type.LOG, newLine))
}
}
fun shutdown() {
runningProjects.forEach {
emptyProjectLog(it)
}
kobaltLog(1, "")
}
}

View file

@ -1,114 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.Args
import com.beust.kobalt.AsciiArt
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.ITask
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project
import com.beust.kobalt.api.ProjectBuildStatus
import com.beust.kobalt.misc.kobaltLog
import com.google.common.collect.ListMultimap
import com.google.common.collect.TreeMultimap
import java.util.concurrent.Callable
/**
* Build the projects in parallel.
*
* The projects are sorted in topological order and then run by the DynamicGraphExecutor in background threads
* wherever appropriate. Inside a project, all the tasks are run sequentially.
*/
class ParallelProjectRunner(val tasksByNames: (Project) -> ListMultimap<String, ITask>,
val dependsOn: TreeMultimap<String, String>,
val reverseDependsOn: TreeMultimap<String, String>, val runBefore: TreeMultimap<String, String>,
val runAfter: TreeMultimap<String, String>,
val alwaysRunAfter: TreeMultimap<String, String>, val args: Args, val pluginInfo: PluginInfo,
val logger: ParallelLogger)
: BaseProjectRunner() {
override fun runProjects(taskInfos: List<TaskManager.TaskInfo>, projects: List<Project>)
: TaskManager .RunTargetResult {
class ProjectTask(val project: Project, val dryRun: Boolean) : Callable<TaskResult2<ProjectTask>> {
override fun toString() = "[ProjectTask " + project.name + "]"
override fun hashCode() = project.hashCode()
override fun equals(other: Any?) : Boolean =
if (other is ProjectTask) other.project.name == project.name
else false
override fun call(): TaskResult2<ProjectTask> {
val context = Kobalt.context!!
runBuildListenersForProject(project, context, true)
val tasksByNames = tasksByNames(project)
val graph = createTaskGraph(project.name, taskInfos, tasksByNames,
dependsOn, reverseDependsOn, runBefore, runAfter, alwaysRunAfter,
ITask::name,
{ task: ITask -> task.plugin.accept(project) })
var lastResult = TaskResult()
logger.onProjectStarted(project.name)
context.logger.log(project.name, 1, AsciiArt.logBox("Building ${project.name}", indent = 5))
while (graph.freeNodes.any()) {
val toProcess = graph.freeNodes
toProcess.forEach { node ->
val tasks = tasksByNames[node.name]
tasks.forEach { task ->
runBuildListenersForTask(project, context, task.name, start = true)
logger.log(project.name, 1,
AsciiArt.taskColor(AsciiArt.horizontalSingleLine + " ${project.name}:${task.name}"))
val thisResult = if (dryRun) TaskResult2(true, value = task) else task.call()
if (lastResult.success) {
lastResult = thisResult
}
runBuildListenersForTask(project, context, task.name, start = false,
success = thisResult.success, testResult = thisResult.testResult)
}
}
graph.freeNodes.forEach { graph.removeNode(it) }
}
logger.onProjectStopped(project.name)
runBuildListenersForProject(project, context, false,
if (lastResult.success) ProjectBuildStatus.SUCCESS else ProjectBuildStatus.FAILED)
return TaskResult2(lastResult.success, errorMessage = lastResult.errorMessage, value = this)
}
}
val factory = object : IThreadWorkerFactory<ProjectTask> {
override fun createWorkers(nodes: Collection<ProjectTask>): List<IWorker<ProjectTask>> {
val result = nodes.map { it ->
object: IWorker<ProjectTask> {
override val priority: Int get() = 0
override val name: String get() = it.project.name
override fun call(): TaskResult2<ProjectTask> {
val tr = it.call()
return tr
}
}
}
return result
}
}
val projectGraph = DynamicGraph<ProjectTask>().apply {
projects.forEach { project ->
addNode(ProjectTask(project, args.dryRun))
project.allProjectDependedOn().forEach {
addEdge(ProjectTask(project, args.dryRun), ProjectTask(it, args.dryRun))
}
}
}
val executor = DynamicGraphExecutor(projectGraph, factory, 5)
kobaltLog(1, "Parallel build starting")
val taskResult = executor.run()
logger.shutdown()
if (! args.sequential) {
executor.dumpHistory()
}
return TaskManager.RunTargetResult(taskResult, emptyList())
}
}

View file

@ -12,7 +12,7 @@ import com.beust.kobalt.api.Project
interface IBuildConfig { interface IBuildConfig {
/** /**
* If at least one build config was found either on the project or the variant, this function * If at least one build config was found either on the project or the variant, this function
* will be used to generateAndSave the BuildConfig file with the correct language. * will be used to generate the BuildConfig file with the correct language.
*/ */
fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant, fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant,
buildConfigs: List<BuildConfig>) : String buildConfigs: List<BuildConfig>) : String

View file

@ -1,96 +0,0 @@
package com.beust.kobalt.internal
import com.beust.kobalt.Args
import com.beust.kobalt.AsciiArt
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.ITask
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project
import com.beust.kobalt.api.ProjectBuildStatus
import com.beust.kobalt.misc.Strings
import com.beust.kobalt.misc.kobaltError
import com.google.common.collect.ListMultimap
import com.google.common.collect.TreeMultimap
import java.util.*
/**
* Build the projects in parallel.
*
* The projects are sorted in topological order and then run by the DynamicGraphExecutor in a single thread.
*/
class SequentialProjectRunner(val tasksByNames: (Project) -> ListMultimap<String, ITask>,
val dependsOn: TreeMultimap<String, String>,
val reverseDependsOn: TreeMultimap<String, String>, val runBefore: TreeMultimap<String, String>,
val runAfter: TreeMultimap<String, String>,
val alwaysRunAfter: TreeMultimap<String, String>, val args: Args, val pluginInfo: PluginInfo)
: BaseProjectRunner() {
override fun runProjects(taskInfos: List<TaskManager.TaskInfo>, projects: List<Project>)
: TaskManager.RunTargetResult {
var result = TaskResult()
val failedProjects = hashSetOf<String>()
val messages = Collections.synchronizedList(arrayListOf<TaskManager.ProfilerInfo>())
val context = Kobalt.context!!
projects.forEach { project ->
val projectName = project.name
fun klog(level: Int, message: String) = context.logger.log(projectName, level, message)
klog(1, AsciiArt.logBox("Building $projectName", indent = 5))
// Does the current project depend on any failed projects?
val fp = project.allProjectDependedOn().filter { failedProjects.contains(it.name) }.map(Project::name)
if (fp.size > 0) {
klog(2, "Marking project $projectName as skipped")
failedProjects.add(project.name)
runBuildListenersForProject(project, context, false, ProjectBuildStatus.SKIPPED)
kobaltError("Not building project ${project.name} since it depends on failed "
+ Strings.pluralize(fp.size, "project")
+ " " + fp.joinToString(","))
} else {
runBuildListenersForProject(project, context, true)
// There can be multiple tasks by the same name (e.g. PackagingPlugin and AndroidPlugin both
// define "install"), so use a multimap
val tasksByNames = tasksByNames(project)
klog(3, "Tasks:")
tasksByNames.keys().forEach {
klog(3, " $it: " + tasksByNames.get(it))
}
val graph = createTaskGraph(project.name, taskInfos, tasksByNames,
dependsOn, reverseDependsOn, runBefore, runAfter, alwaysRunAfter,
ITask::name,
{ task: ITask -> task.plugin.accept(project) })
//
// Now that we have a full graph, run it
//
klog(2, "About to run graph:\n ${graph.dump()} ")
val factory = object : IThreadWorkerFactory<ITask> {
override fun createWorkers(nodes: Collection<ITask>)
= nodes.map { TaskWorker(listOf(it), args.dryRun, pluginInfo) }
}
val executor = DynamicGraphExecutor(graph, factory)
val thisResult = executor.run()
if (! thisResult.success) {
klog(2, "Marking project ${project.name} as failed")
failedProjects.add(project.name)
}
runBuildListenersForProject(project, context, false,
if (thisResult.success) ProjectBuildStatus.SUCCESS else ProjectBuildStatus.FAILED)
if (result.success) {
result = thisResult
}
}
}
return TaskManager.RunTargetResult(result, messages)
}
}

View file

@ -6,6 +6,5 @@ package com.beust.kobalt.internal
*/ */
class SpekRunner : JUnitRunner() { class SpekRunner : JUnitRunner() {
override val dependencyName = "org.jetbrains.spek" override val dependencyName = "org.jetbrains.spek"
override val runnerName = "Spek"
} }

View file

@ -4,10 +4,14 @@ import com.beust.kobalt.*
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.IncrementalTask import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.misc.Topological import com.beust.kobalt.misc.Strings
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.benchmarkMillis
import com.beust.kobalt.misc.kobaltError
import com.beust.kobalt.misc.log
import com.google.common.annotations.VisibleForTesting
import com.google.common.collect.ArrayListMultimap import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.ListMultimap import com.google.common.collect.ListMultimap
import com.google.common.collect.Multimap
import com.google.common.collect.TreeMultimap import com.google.common.collect.TreeMultimap
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.* import java.util.*
@ -16,8 +20,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class TaskManager @Inject constructor(val args: Args, class TaskManager @Inject constructor(val args: Args,
val incrementalManagerFactory: IncrementalManager.IFactory, val incrementalManagerFactory: IncrementalManager.IFactory) {
val kobaltLog: ParallelLogger) {
private val dependsOn = TreeMultimap.create<String, String>() private val dependsOn = TreeMultimap.create<String, String>()
private val reverseDependsOn = TreeMultimap.create<String, String>() private val reverseDependsOn = TreeMultimap.create<String, String>()
private val runBefore = TreeMultimap.create<String, String>() private val runBefore = TreeMultimap.create<String, String>()
@ -42,7 +45,7 @@ class TaskManager @Inject constructor(val args: Args,
/** /**
* Ordering: task2 runs after task 1. * Ordering: task2 runs after task 1.
*/ */
fun runAfter(task1: String, task2: String) = runAfter.put(task1, task2) fun runAfter(task1: String, task2: String) = runAfter.put(task2, task1)
/** /**
* Wrapper task: task2 runs after task 1. * Wrapper task: task2 runs after task 1.
@ -53,16 +56,14 @@ class TaskManager @Inject constructor(val args: Args,
constructor(project: String, task: String) : this(project + ":" + task) constructor(project: String, task: String) : this(project + ":" + task)
val project: String? val project: String?
get() = if (id.contains(':')) id.split(':')[0] else null get() = if (id.contains(":")) id.split(":")[0] else null
val taskName: String val taskName: String
get() = if (id.contains(':')) id.split(':')[1] else id get() = if (id.contains(":")) id.split(":")[1] else id
fun matches(projectName: String) = project == null || project == projectName fun matches(projectName: String) = project == null || project == projectName
override fun toString() = id
} }
class RunTargetResult(val taskResult: TaskResult, val timings: List<ProfilerInfo>) class RunTargetResult(val exitCode: Int, val messages: List<String>)
/** /**
* @return the list of tasks available for the given project. * @return the list of tasks available for the given project.
@ -80,96 +81,245 @@ class TaskManager @Inject constructor(val args: Args,
} }
} }
// @Inject fun runTargets(passedTaskNames: List<String>, projects: List<Project>): RunTargetResult {
// lateinit var pluginInfo: PluginInfo var result = 0
val failedProjects = hashSetOf<String>()
val messages = Collections.synchronizedList(arrayListOf<String>())
val taskNames = calculateDependentTaskNames(passedTaskNames, projects)
projects.forEach { project ->
AsciiArt.logBox("Building ${project.name}")
fun runTargets(passedTaskNames: List<String>, allProjects: List<Project>): RunTargetResult { // Does the current project depend on any failed projects?
// Check whether tasks passed at command line exist val fp = project.projectExtra.dependsOn.filter {
passedTaskNames.forEach { failedProjects.contains(it.name)
if (!hasTask(TaskInfo(it))) }.map {
throw KobaltException("Unknown task: $it") it.name
} }
val pluginInfo = Kobalt.INJECTOR.getInstance(PluginInfo::class.java) if (fp.size > 0) {
var taskInfos = calculateDependentTaskNames(passedTaskNames, allProjects) log(2, "Marking project ${project.name} as skipped")
failedProjects.add(project.name)
// Remove non existing tasks (e.g. dynamic task defined for a single project) kobaltError("Not building project ${project.name} since it depends on failed "
taskInfos = taskInfos.filter { hasTask(it) } + Strings.pluralize(fp.size, "project")
+ " " + fp.joinToString(","))
val projectsToRun = findProjectsToRun(taskInfos, allProjects)
val projectRunner =
if (args.sequential) {
SequentialProjectRunner({ p -> tasksByNames(p) }, dependsOn,
reverseDependsOn, runBefore, runAfter, alwaysRunAfter, args, pluginInfo)
} else { } else {
ParallelProjectRunner({ p -> tasksByNames(p) }, dependsOn, // There can be multiple tasks by the same name (e.g. PackagingPlugin and AndroidPlugin both
reverseDependsOn, runBefore, runAfter, alwaysRunAfter, args, pluginInfo, kobaltLog) // define "install"), so use a multimap
val tasksByNames = tasksByNames(project)
log(3, "Tasks:")
tasksByNames.keys().forEach {
log(3, " $it: " + tasksByNames.get(it))
}
val graph = createGraph2(project.name, taskNames, tasksByNames,
dependsOn, reverseDependsOn, runBefore, runAfter, alwaysRunAfter,
{ task: ITask -> task.name },
{ task: ITask -> task.plugin.accept(project) })
//
// Now that we have a full graph, run it
//
log(2, "About to run graph:\n ${graph.dump()} ")
val factory = object : IThreadWorkerFactory<ITask> {
override fun createWorkers(nodes: Collection<ITask>)
= nodes.map { TaskWorker(listOf(it), args.dryRun, messages) }
}
val executor = DynamicGraphExecutor(graph, factory)
val thisResult = executor.run()
if (thisResult != 0) {
log(2, "Marking project ${project.name} as failed")
failedProjects.add(project.name)
}
if (result == 0) {
result = thisResult
}
} }
return projectRunner.runProjects(taskInfos, projectsToRun)
}
/**
* Determine which projects to run based on the request tasks. Also make sure that all the requested projects
* exist.
*/
private fun findProjectsToRun(taskInfos: List<TaskInfo>, projects: List<Project>) : List<Project> {
// Validate projects
val result = LinkedHashSet<Project>()
val projectMap = HashMap<String, Project>().apply {
projects.forEach { put(it.name, it)}
} }
return RunTargetResult(result, messages)
// Extract all the projects we need to run from the tasks
taskInfos.forEach {
val p = it.project
if (p != null && ! projectMap.containsKey(p)) {
throw KobaltException("Unknown project: ${it.project}")
}
result.add(projectMap[it.project]!!)
}
// If at least one task didn't specify a project, run them all
return if (result.any()) result.toList() else projects
} }
class ProfilerInfo(val taskName: String, val durationMillis: Long)
/** /**
* If the user wants to run a single task on a single project (e.g. "kobalt:assemble"), we need to * If the user wants to run a single task on a single project (e.g. "kobalt:assemble"), we need to
* see if that project depends on others and if it does, compile these projects first. This * see if that project depends on others and if it does, invoke these tasks on all of them. This
* function returns all these task names (including the dependent ones). * function returns all these task names (including dependent).
*/ */
fun calculateDependentTaskNames(taskNames: List<String>, projects: List<Project>): List<TaskInfo> { private fun calculateDependentTaskNames(taskNames: List<String>, projects: List<Project>): List<String> {
return taskNames.flatMap { calculateDependentTaskNames(it, projects) } val projectMap = hashMapOf<String, Project>().apply {
} projects.forEach { put(it.name, it)}
}
private fun calculateDependentTaskNames(taskName: String, projects: List<Project>): List<TaskInfo> { val result = ArrayList(taskNames)
fun sortProjectsTopologically(projects: List<Project>) : List<Project> { val toProcess = ArrayList(taskNames)
val topological = Topological<Project>().apply { val newToProcess = arrayListOf<String>()
projects.forEach { project -> val seen = hashSetOf<String>()
addNode(project) var stop = false
project.allProjectDependedOn().forEach { while (! stop) {
addEdge(project, it) toProcess.forEach { taskName ->
val ti = TaskInfo(taskName)
projectMap[ti.project]?.let { project ->
project.projectExtra.dependsOn.forEach { dp ->
val newTask = TaskInfo(dp.projectName, ti.taskName).id
result.add(newTask)
if (! seen.contains(newTask)) {
newToProcess.add(newTask)
seen.add(newTask)
}
} }
} }
} }
val sortedProjects = topological.sort() stop = newToProcess.isEmpty()
return sortedProjects toProcess.clear()
toProcess.addAll(newToProcess)
newToProcess.clear()
} }
val ti = TaskInfo(taskName) return result
if (ti.project == null) { }
val result = sortProjectsTopologically(projects).map { TaskInfo(it.name, taskName) }
return result val LOG_LEVEL = 3
} else {
val rootProject = projects.find { it.name == ti.project }!! /**
val allProjects = DynamicGraph.transitiveClosure(rootProject, Project::allProjectDependedOn) * Create a graph representing the tasks and their dependencies. That graph will then be run
val sortedProjects = sortProjectsTopologically(allProjects) * in topological order.
val sortedMaps = sortedProjects.map { TaskInfo(it.name, "compile")} *
val result = sortedMaps.subList(0, sortedMaps.size - 1) + listOf(ti) * @taskNames is the list of tasks requested by the user. @nodeMap maps these tasks to the nodes
return result * we'll be adding to the graph while @toName extracts the name of a node.
*/
@VisibleForTesting
fun <T> createGraph2(projectName: String, taskNames: List<String>, nodeMap: Multimap<String, T>,
dependsOn: Multimap<String, String>,
reverseDependsOn: Multimap<String, String>,
runBefore: Multimap<String, String>,
runAfter: Multimap<String, String>,
alwaysRunAfter: Multimap<String, String>,
toName: (T) -> String,
accept: (T) -> Boolean):
DynamicGraph<T> {
val result = DynamicGraph<T>()
val newToProcess = arrayListOf<T>()
val seen = hashSetOf<String>()
//
// Reverse the always map so that tasks can be looked up.
//
val always = ArrayListMultimap.create<String, String>().apply {
alwaysRunAfter.keySet().forEach { k ->
alwaysRunAfter[k].forEach { v ->
put(v, k)
}
}
} }
//
// Turn the task names into the more useful TaskInfo and do some sanity checking on the way
//
val taskInfos = taskNames.map { TaskInfo(it) }.filter {
if (!nodeMap.keys().contains(it.taskName)) {
throw KobaltException("Unknown task: $it")
}
it.matches(projectName)
}
// The nodes we need to process, initialized with the set of tasks requested by the user.
// As we run the graph and discover dependencies, new nodes get added to @param[newToProcess]. At
// the end of the loop, @param[toProcess] is cleared and all the new nodes get added to it. Then we loop.
val toProcess = ArrayList(taskInfos)
while (toProcess.size > 0) {
/**
* Add an edge from @param from to all its tasks.
*/
fun addEdge(result: DynamicGraph<T>, from: String, to: String, newToProcess: ArrayList<T>, text: String) {
val froms = nodeMap[from]
froms.forEach { f: T ->
nodeMap[to].forEach { t: T ->
val tn = toName(t)
log(LOG_LEVEL, " Adding edge ($text) $f -> $t")
result.addEdge(f, t)
newToProcess.add(t)
}
}
}
/**
* Whenever a task is added to the graph, we also add its alwaysRunAfter tasks.
*/
fun processAlways(always: Multimap<String, String>, node: T) {
log(LOG_LEVEL, " Processing always for $node")
always[toName(node)]?.let { to: Collection<String> ->
to.forEach { t ->
nodeMap[t].forEach { from ->
log(LOG_LEVEL, " Adding always edge $from -> $node")
result.addEdge(from, node)
}
}
log(LOG_LEVEL, " ... done processing always for $node")
}
}
log(LOG_LEVEL, " Current batch to process: $toProcess")
//
// Move dependsOn + reverseDependsOn in one multimap called allDepends
//
val allDependsOn = ArrayListMultimap.create<String, String>()
dependsOn.keySet().forEach { key ->
dependsOn[key].forEach { value ->
allDependsOn.put(key, value)
}
}
reverseDependsOn.keySet().forEach { key ->
reverseDependsOn[key].forEach { value ->
allDependsOn.put(value, key)
}
}
//
// Process each node one by one
//
toProcess.forEach { taskInfo ->
val taskName = taskInfo.taskName
log(LOG_LEVEL, " ***** Current node: $taskName")
nodeMap[taskName].forEach {
result.addNode(it)
processAlways(always, it)
}
//
// dependsOn and reverseDependsOn are considered for all tasks, explicit and implicit
//
allDependsOn[taskName].forEach { to ->
addEdge(result, taskName, to, newToProcess, "dependsOn")
}
//
// runBefore and runAfter (task ordering) are only considered for explicit tasks (tasks that were
// explicitly requested by the user)
//
runBefore[taskName].forEach { from ->
if (taskNames.contains(from)) {
addEdge(result, from, taskName, newToProcess, "runBefore")
}
}
runAfter[taskName].forEach { to ->
if (taskNames.contains(to)) {
addEdge(result, taskName, to, newToProcess, "runAfter")
}
}
seen.add(taskName)
}
newToProcess.forEach { processAlways(always, it) }
toProcess.clear()
toProcess.addAll(newToProcess.filter { ! seen.contains(toName(it))}.map { TaskInfo(toName(it)) })
newToProcess.clear()
}
return result
} }
///// /////
@ -196,7 +346,6 @@ class TaskManager @Inject constructor(val args: Args,
= TaskAnnotation(method, plugin, ta.name, ta.description, ta.group, ta.dependsOn, ta.reverseDependsOn, = TaskAnnotation(method, plugin, ta.name, ta.description, ta.group, ta.dependsOn, ta.reverseDependsOn,
ta.runBefore, ta.runAfter, ta.alwaysRunAfter, ta.runBefore, ta.runAfter, ta.alwaysRunAfter,
{ project -> { project ->
Kobalt.context?.variant = Variant()
method.invoke(plugin, project) as TaskResult method.invoke(plugin, project) as TaskResult
}) })
@ -228,14 +377,16 @@ class TaskManager @Inject constructor(val args: Args,
*/ */
fun computePluginTasks(projects: List<Project>) { fun computePluginTasks(projects: List<Project>) {
installAnnotationTasks(projects) installAnnotationTasks(projects)
installDynamicTasks() installDynamicTasks(projects)
} }
private fun installDynamicTasks() { private fun installDynamicTasks(projects: List<Project>) {
dynamicTasks.forEach { task -> dynamicTasks.forEach { task ->
addTask(task.plugin, task.project, task.name, task.doc, task.group, projects.filter { task.plugin.accept(it) }.forEach { project ->
task.dependsOn, task.reverseDependsOn, task.runBefore, task.runAfter, task.alwaysRunAfter, addTask(task.plugin, project, task.name, task.doc, task.group,
task.closure) task.dependsOn, task.reverseDependsOn, task.runBefore, task.runAfter, task.alwaysRunAfter,
task.closure)
}
} }
} }
@ -244,7 +395,7 @@ class TaskManager @Inject constructor(val args: Args,
val method = staticTask.method val method = staticTask.method
val methodName = method.declaringClass.toString() + "." + method.name val methodName = method.declaringClass.toString() + "." + method.name
kobaltLog(3, " Found task:${staticTask.name} method: $methodName") log(3, " Found task:${staticTask.name} method: $methodName")
val plugin = staticTask.plugin val plugin = staticTask.plugin
projects.filter { plugin.accept(it) }.forEach { project -> projects.filter { plugin.accept(it) }.forEach { project ->
@ -272,8 +423,7 @@ class TaskManager @Inject constructor(val args: Args,
object : BasePluginTask(plugin, name, description, group, project) { object : BasePluginTask(plugin, name, description, group, project) {
override fun call(): TaskResult2<ITask> { override fun call(): TaskResult2<ITask> {
val taskResult = task(project) val taskResult = task(project)
return TaskResult2(taskResult.success, errorMessage = taskResult.errorMessage, value = this, return TaskResult2(taskResult.success, taskResult.errorMessage, this)
testResult = taskResult.testResult)
} }
}) })
dependsOn.forEach { dependsOn(it, name) } dependsOn.forEach { dependsOn(it, name) }
@ -283,12 +433,6 @@ class TaskManager @Inject constructor(val args: Args,
alwaysRunAfter.forEach { alwaysRunAfter(it, name) } alwaysRunAfter.forEach { alwaysRunAfter(it, name) }
} }
fun hasTask(ti: TaskInfo): Boolean {
val taskName = ti.taskName
val project = ti.project
return annotationTasks.any { taskName == it.name && (project == null || project == it.project.name) }
}
/** /**
* Invoked by the server whenever it's done processing a command so the state can be reset for the next command. * Invoked by the server whenever it's done processing a command so the state can be reset for the next command.
*/ */
@ -303,32 +447,30 @@ class TaskManager @Inject constructor(val args: Args,
///// /////
} }
class TaskWorker(val tasks: List<ITask>, val dryRun: Boolean, val pluginInfo: PluginInfo) : IWorker<ITask> { class TaskWorker(val tasks: List<ITask>, val dryRun: Boolean, val messages: MutableList<String>)
: IWorker<ITask> {
override fun call() : TaskResult2<ITask> { override fun call() : TaskResult2<ITask> {
if (tasks.size > 0) { if (tasks.size > 0) {
tasks[0].let { tasks[0].let {
kobaltLog(1, AsciiArt.taskColor(AsciiArt.horizontalSingleLine + " ${it.project.name}:${it.name}")) log(1, AsciiArt.taskColor(AsciiArt.horizontalSingleLine + " ${it.project.name}:${it.name}"))
} }
} }
var success = true var success = true
val errorMessages = arrayListOf<String>() val errorMessages = arrayListOf<String>()
val context = Kobalt.context!!
tasks.forEach { tasks.forEach {
val name = it.project.name + ":" + it.name val name = it.project.name + ":" + it.name
BaseProjectRunner.runBuildListenersForTask(it.project, context, name, start = true) val time = benchmarkMillis {
val tr = if (dryRun) TaskResult() else it.call() val tr = if (dryRun) TaskResult() else it.call()
BaseProjectRunner.runBuildListenersForTask(it.project, context, name, start = false, success = tr.success) success = success and tr.success
success = success and tr.success if (tr.errorMessage != null) errorMessages.add(tr.errorMessage)
tr.errorMessage?.let {
errorMessages.add(it)
} }
messages.add("$name: $time ms")
} }
return TaskResult2(success, errorMessage = errorMessages.joinToString("\n"), value = tasks[0]) return TaskResult2(success, errorMessages.joinToString("\n"), tasks[0])
} }
// override val timeOut : Long = 10000 // override val timeOut : Long = 10000
override val priority: Int = 0 override val priority: Int = 0
override val name: String get() = "[Taskworker " + tasks.map(ITask::toString).joinToString(",") + "]"
} }

View file

@ -1,53 +1,25 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.AsciiArt
import com.beust.kobalt.TestConfig import com.beust.kobalt.TestConfig
import com.beust.kobalt.TestResult
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.maven.aether.AetherDependency import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.* import com.beust.kobalt.misc.warn
import org.testng.remote.RemoteArgs
import org.testng.remote.strprotocol.JsonMessageSender
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.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() { class TestNgRunner : GenericTestRunner() {
override val mainClass = "org.testng.TestNG" override val mainClass = "org.testng.TestNG"
override val dependencyName = "testng" override val dependencyName = "testng"
override val annotationPackage = "org.testng"
override val runnerName = "TestNG"
private fun defaultOutputWithoutProjectDir(project: Project) fun defaultOutput(project: Project) = KFiles.joinDir(project.buildDirectory, "test-output")
= 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<IClasspathDependency>, override fun args(project: Project, classpath: List<IClasspathDependency>, testConfig: TestConfig)
testConfig: TestConfig) = arrayListOf<String>().apply { = arrayListOf<String>().apply {
var addOutput = true
if (KobaltLogger.isQuiet) { testConfig.testArgs.forEach { arg ->
add("-log") if (arg == "-d") addOutput = false
add("0")
}
if (testConfig.testArgs.none { it == "-d" }) {
add("-d")
// 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) { if (testConfig.testArgs.size == 0) {
@ -56,213 +28,26 @@ class TestNgRunner : GenericTestRunner() {
if (testngXml.exists()) { if (testngXml.exists()) {
add(testngXml.absolutePath) add(testngXml.absolutePath)
} else { } else {
val testClasses = findTestClasses(project, context, testConfig) val testClasses = findTestClasses(project, testConfig)
if (testClasses.isNotEmpty()) { if (testClasses.size > 0) {
if (addOutput) {
add("-d")
add(defaultOutput(project))
}
addAll(testConfig.testArgs) addAll(testConfig.testArgs)
add("-testclass") add("-testclass")
add(testClasses.joinToString(",")) add(testClasses.joinToString(","))
} else { } else {
if (!testConfig.isDefault) warn("Couldn't find any test classes for ${project.name}") warn("Couldn't find any test classes for ${project.name}")
// else do nothing: since the user didn't specify an explicit test{} directive, not finding
// any test sources is not a problem
} }
} }
} else { } else {
if (addOutput) {
add("-d")
add(defaultOutput(project))
}
addAll(testConfig.testArgs) addAll(testConfig.testArgs)
} }
} }
/**
* Extract test results from testng-results.xml and initialize shortMessage.
*/
override fun onFinish(project: Project) {
File(defaultOutput(project), "testng-results.xml").let { file ->
val ins = InputSource(FileReader(file))
val doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ins)
val root = doc.documentElement
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<String>()
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) {
"failed" -> failed = Integer.parseInt(attribute.value)
"skipped" -> skipped = Integer.parseInt(attribute.value)
"passed" -> passed = Integer.parseInt(attribute.value)
}
}
if (failed == 0) {
shortMessage = "$passed tests"
} else if (failed > 0) {
shortMessage = "$failed failed" + (if (skipped > 0) ", $skipped skipped" else "") + " tests"
longMessage = "Failed tests:\n " + failedMethods.joinToString("\n ")
}
}
}
val VERSION_6_10 = StringVersion("6.10")
fun _runTests(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
// override fun runTests(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
configName: String): TestResult {
val testConfig = project.testConfigs.firstOrNull { it.name == configName }
if (testConfig != null) {
context.logger.log(project.name, 1, "Running enhanced TestNG runner")
val testngDependency = (project.testDependencies.filter { it.id.contains("testng") }
.firstOrNull() as AetherDependency).version
val versions = findRemoteRunnerVersion(testngDependency)
val useOldRunner = System.getProperty("testng.oldRunner") != null
val result =
if (versions != null && ! useOldRunner) {
context.logger.log(project.name, 1, "Modern TestNG, displaying colors")
displayPrettyColors(project, context, classpath, testConfig, versions)
} else {
context.logger.log(project.name, 1, "Older TestNG ($testngDependency), using the old runner")
super.runTests(project, context, classpath, configName)
}
return result
} else {
return TestResult(true)
}
}
private fun findRemoteRunnerVersion(testngVersion: String) : Pair<String, String>? {
val tng = StringVersion(testngVersion)
val result =
if (tng >= VERSION_6_10) Pair(testngVersion, "testng-remote6_10")
else if (tng >= StringVersion("6.9.10")) Pair("6.9.10", "testng-remote6_9_10")
else if (tng >= StringVersion("6.9.7")) Pair("6.9.7", "testng-remote6_9_7")
else if (tng >= StringVersion("6.5.1")) Pair("6.5.1", "testng-remote6_5_0")
else if (tng >= StringVersion("6.0")) Pair("6.0", "testng-remote6_0")
else null
return result
}
private fun displayPrettyColors(project: Project, context: KobaltContext,
classpath: List<IClasspathDependency>, testConfig: TestConfig, versions: Pair<String, String>)
: TestResult {
val port = 2345
// launchRemoteServer(project, context, classpath, testConfig, versions, port)
val mh = MessageHub(JsonMessageSender("localhost", port, true))
mh.setDebug(true)
mh.initReceiver()
val passed = arrayListOf<String>()
data class FailedTest(val method: String, val cls: String, val stackTrace: String)
val failed = arrayListOf<FailedTest>()
val skipped = arrayListOf<String>()
fun d(n: Int, color: String)
= AsciiArt.wrap(String.format("%4d", n), color)
fun red(s: String) = AsciiArt.wrap(s, AsciiArt.RED)
fun green(s: String) = AsciiArt.wrap(s, AsciiArt.GREEN)
fun yellow(s: String) = AsciiArt.wrap(s, AsciiArt.YELLOW)
try {
var message = mh.receiveMessage()
kobaltLog(1, "")
kobaltLog(1, green("PASSED") + " | " + red("FAILED") + " | " + yellow("SKIPPED"))
while (message != null) {
message = mh.receiveMessage()
if (message is TestResultMessage) {
when (message.result) {
MessageHelper.PASSED_TEST -> passed.add(message.name)
MessageHelper.FAILED_TEST -> failed.add(FailedTest(message.testClass,
message.method, message.stackTrace))
MessageHelper.SKIPPED_TEST -> skipped.add(message.name)
}
}
if (!KobaltLogger.isQuiet) {
print("\r " + d(passed.size, AsciiArt.GREEN)
+ " | " + d(failed.size, AsciiArt.RED)
+ " | " + d(skipped.size, AsciiArt.YELLOW))
}
}
} catch(ex: IOException) {
kobaltLog(1, "Exception: ${ex.message}")
}
kobaltLog(1, "\nPassed: " + passed.size + ", Failed: " + failed.size + ", Skipped: " + skipped.size)
failed.forEach {
val top = it.stackTrace.substring(0, it.stackTrace.indexOf("\n"))
kobaltLog(1, " " + it.cls + "." + it.method + "\n " + top)
}
return TestResult(failed.isEmpty() && skipped.isEmpty())
}
fun launchRemoteServer(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
testConfig: TestConfig, versions: Pair<String, String>, port: Int) {
val testngVersion = versions.first
val remoteRunnerVersion = versions.second
val dep = with(context.dependencyManager) {
val jf = create("org.testng.testng-remote:testng-remote:1.3.0")
val tr = create("org.testng.testng-remote:$remoteRunnerVersion:1.3.0")
val testng = create("org.testng:testng:6.11")
transitiveClosure(kotlin.collections.listOf(jf, tr /*, testng */))
}
val cp = (classpath + dep).distinct().map { it.jarFile.get() }
.joinToString(File.pathSeparator)
val calculatedArgs = args(project, context, classpath, testConfig)
val jvmArgs = arrayListOf("-classpath", cp)
if (testConfig.jvmArgs.any()) {
jvmArgs.addAll(testConfig.jvmArgs)
}
val remoteArgs = listOf(
"org.testng.remote.RemoteTestNG",
"-serport", port.toString(),
"-version", testngVersion,
"-dontexit",
RemoteArgs.PROTOCOL,
"json")
val passedArgs = jvmArgs + remoteArgs + calculatedArgs
Thread {
runCommand {
command = "java"
directory = File(project.directory)
args = passedArgs
}
}.start()
// Thread {
// val args2 = arrayOf("-serport", port.toString(), "-dontexit", RemoteArgs.PROTOCOL, "json",
// "-version", "6.10",
// "src/test/resources/testng.xml")
// RemoteTestNG.main(args2)
// }.start()
}
}
fun main(args: Array<String>) {
fun d(n: Int, color: String)
= AsciiArt.wrap(String.format("%4d", n), color)
if (!KobaltLogger.isQuiet) {
println("PASSED | FAILED | SKIPPED")
repeat(20) { i ->
print("\r " + d(i, AsciiArt.GREEN) + " | " + d(i * 2, AsciiArt.RED) + " | " + d(i, AsciiArt.YELLOW))
Thread.sleep(500)
}
println("")
}
} }

Some files were not shown because too many files have changed in this diff Show more