diff --git a/.travis.yml b/.travis.yml
index 46fdae3d..0c1d3b1d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,4 +10,4 @@ jdk:
install: true
-script: ./kobaltw assemble test --log 1
+script: ./build-travis.sh
diff --git a/build-travis.sh b/build-travis.sh
new file mode 100755
index 00000000..467849b9
--- /dev/null
+++ b/build-travis.sh
@@ -0,0 +1,4 @@
+java -Xmx2048m -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $* assemble
+
+java -Xmx2048m -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $* test
+
diff --git a/dist/kobaltw.bat b/dist/kobaltw.bat
index 52e2d636..8ce6a621 100644
--- a/dist/kobaltw.bat
+++ b/dist/kobaltw.bat
@@ -1,2 +1,2 @@
@echo off
-java -jar "%~dp0/kobalt/wrapper/kobalt-wrapper.jar" %*
+java -jar "%~dp0/../kobalt/wrapper/kobalt-wrapper.jar" %*
diff --git a/kobalt.iml b/kobalt.iml
index 384e6859..e9146d07 100644
--- a/kobalt.iml
+++ b/kobalt.iml
@@ -3,9 +3,7 @@
-
-
@@ -16,7 +14,7 @@
-
+
@@ -25,7 +23,7 @@
-
+
@@ -34,7 +32,7 @@
-
+
@@ -43,7 +41,7 @@
-
+
@@ -52,7 +50,7 @@
-
+
@@ -61,7 +59,7 @@
-
+
@@ -70,7 +68,7 @@
-
+
@@ -79,16 +77,16 @@
-
+
-
+
-
+
@@ -97,7 +95,7 @@
-
+
@@ -106,7 +104,7 @@
-
+
@@ -115,7 +113,7 @@
-
+
@@ -124,7 +122,7 @@
-
+
@@ -133,7 +131,7 @@
-
+
@@ -142,7 +140,7 @@
-
+
@@ -151,7 +149,7 @@
-
+
@@ -160,7 +158,7 @@
-
+
@@ -169,7 +167,7 @@
-
+
@@ -178,7 +176,7 @@
-
+
@@ -187,7 +185,7 @@
-
+
@@ -196,7 +194,7 @@
-
+
@@ -205,7 +203,7 @@
-
+
@@ -214,7 +212,7 @@
-
+
@@ -223,7 +221,7 @@
-
+
@@ -232,7 +230,7 @@
-
+
@@ -241,7 +239,7 @@
-
+
@@ -250,7 +248,7 @@
-
+
@@ -259,7 +257,7 @@
-
+
@@ -268,7 +266,7 @@
-
+
@@ -277,7 +275,7 @@
-
+
@@ -286,7 +284,7 @@
-
+
@@ -295,7 +293,7 @@
-
+
@@ -304,7 +302,7 @@
-
+
@@ -313,7 +311,7 @@
-
+
@@ -322,7 +320,7 @@
-
+
@@ -331,7 +329,7 @@
-
+
@@ -340,7 +338,7 @@
-
+
@@ -349,7 +347,7 @@
-
+
@@ -358,7 +356,7 @@
-
+
@@ -367,12 +365,13 @@
-
+
+
-
\ No newline at end of file
+
diff --git a/kobalt/src/Build.kt b/kobalt/src/Build.kt
index afd4efe7..af5b0b66 100644
--- a/kobalt/src/Build.kt
+++ b/kobalt/src/Build.kt
@@ -21,13 +21,11 @@ import java.nio.file.StandardCopyOption
object Versions {
val okhttp = "3.2.0"
val okio = "1.6.0"
- val retrofit = "2.0.0"
+ val retrofit = "2.0.2"
val gson = "2.6.2"
val aether = "1.1.0"
val sonatypeAether = "1.13.1"
val maven = "3.3.9"
- val jersey = "2.22.2"
- val jetty = "8.1.19.v20160209" // "9.3.9.M1"
}
val wrapper = project {
@@ -69,16 +67,16 @@ val kobaltPluginApi = project {
developerConnection = "git@github.com:cbeust/kobalt.git")
dependencies {
- compile("org.jetbrains.kotlinx:kotlinx.dom:0.0.10",
-
+ compile(
"com.google.inject:guice:4.0",
"com.google.inject.extensions:guice-assistedinject:4.0",
"javax.inject:javax.inject:1",
- "com.google.guava:guava:19.0-rc2",
+ "com.google.guava:guava:19.0",
"org.apache.maven:maven-model:${Versions.maven}",
- "io.reactivex:rxjava:1.0.16",
- "com.google.code.gson:gson:${Versions.gson}",
+ "io.reactivex:rxjava:1.1.5",
"com.squareup.okio:okio:${Versions.okio}",
+ "com.google.code.gson:gson:${Versions.gson}",
+ "com.squareup.okhttp3:okhttp:${Versions.okhttp}",
"com.squareup.retrofit2:retrofit:${Versions.retrofit}",
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
"com.beust:jcommander:1.48",
@@ -126,7 +124,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
dependencies {
// Used by the plugins
- compile("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.0")
+ compile("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.2")
// Used by the main app
compile("com.github.spullara.mustache.java:compiler:0.9.1",
@@ -137,7 +135,6 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
"org.apache.maven:maven-model:${Versions.maven}",
"com.google.code.findbugs:jsr305:3.0.1",
"com.google.code.gson:gson:${Versions.gson}",
- "com.squareup.okhttp3:okhttp:${Versions.okhttp}",
"com.squareup.retrofit2:retrofit:${Versions.retrofit}",
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
"org.codehaus.plexus:plexus-utils:3.0.22",
@@ -159,7 +156,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
}
dependenciesTest {
- compile("org.testng:testng:6.9.10",
+ compile("org.testng:testng:6.9.11",
"org.assertj:assertj-core:3.4.1")
}
diff --git a/kobalt/wrapper/kobalt-wrapper.properties b/kobalt/wrapper/kobalt-wrapper.properties
index 7fe637c5..25ce6fa8 100644
--- a/kobalt/wrapper/kobalt-wrapper.properties
+++ b/kobalt/wrapper/kobalt-wrapper.properties
@@ -1 +1 @@
-kobalt.version=0.789
\ No newline at end of file
+kobalt.version=0.814
\ No newline at end of file
diff --git a/kobaltw.bat b/kobaltw.bat
index 8ce6a621..52e2d636 100644
--- a/kobaltw.bat
+++ b/kobaltw.bat
@@ -1,2 +1,2 @@
@echo off
-java -jar "%~dp0/../kobalt/wrapper/kobalt-wrapper.jar" %*
+java -jar "%~dp0/kobalt/wrapper/kobalt-wrapper.jar" %*
diff --git a/modules/kobalt-plugin-api/kobalt-plugin-api.iml b/modules/kobalt-plugin-api/kobalt-plugin-api.iml
index 7e463927..40595e33 100644
--- a/modules/kobalt-plugin-api/kobalt-plugin-api.iml
+++ b/modules/kobalt-plugin-api/kobalt-plugin-api.iml
@@ -12,9 +12,9 @@
-
+
-
+
@@ -23,7 +23,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
@@ -41,7 +41,7 @@
-
+
@@ -50,7 +50,7 @@
-
+
@@ -59,7 +59,7 @@
-
+
@@ -68,7 +68,7 @@
-
+
@@ -77,7 +77,7 @@
-
+
@@ -86,7 +86,7 @@
-
+
@@ -95,7 +95,7 @@
-
+
@@ -104,7 +104,7 @@
-
+
@@ -113,7 +113,7 @@
-
+
@@ -122,7 +122,7 @@
-
+
@@ -131,7 +131,7 @@
-
+
@@ -140,7 +140,7 @@
-
+
@@ -149,7 +149,7 @@
-
+
@@ -158,7 +158,7 @@
-
+
@@ -167,7 +167,7 @@
-
+
@@ -176,7 +176,7 @@
-
+
@@ -185,7 +185,7 @@
-
+
@@ -194,7 +194,7 @@
-
+
@@ -203,7 +203,7 @@
-
+
@@ -212,7 +212,7 @@
-
+
@@ -221,7 +221,7 @@
-
+
@@ -230,7 +230,7 @@
-
+
@@ -239,7 +239,7 @@
-
+
@@ -248,7 +248,7 @@
-
+
@@ -257,7 +257,7 @@
-
+
@@ -266,7 +266,7 @@
-
+
@@ -275,7 +275,7 @@
-
+
@@ -284,7 +284,7 @@
-
+
@@ -293,7 +293,7 @@
-
+
@@ -302,7 +302,7 @@
-
+
@@ -311,7 +311,7 @@
-
+
@@ -320,7 +320,7 @@
-
+
@@ -329,7 +329,7 @@
-
+
@@ -338,7 +338,7 @@
-
+
@@ -347,7 +347,7 @@
-
+
@@ -356,7 +356,7 @@
-
+
@@ -365,7 +365,7 @@
-
+
@@ -374,7 +374,7 @@
-
+
@@ -383,16 +383,16 @@
-
+
-
+
-
+
@@ -401,7 +401,7 @@
-
+
@@ -410,7 +410,7 @@
-
+
@@ -419,7 +419,7 @@
-
+
@@ -428,7 +428,7 @@
-
+
@@ -437,11 +437,12 @@
-
+
+
-
\ No newline at end of file
+
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt
index 7501cec5..03c5e134 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt
@@ -45,6 +45,10 @@ class Args {
@Parameter(names = arrayOf("--log"), description = "Define the log level (1-3)")
var log: Int = 1
+ @Parameter(names = arrayOf("--forceIncremental"),
+ description = "Force the build to be incremental even if the build file was modified")
+ var forceIncremental: Boolean = false
+
@Parameter(names = arrayOf("--noIncremental"), description = "Turn off incremental builds")
var noIncremental: Boolean = false
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/JarGenerator.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/JarGenerator.kt
index d7197526..d99c59f5 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/JarGenerator.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/JarGenerator.kt
@@ -2,10 +2,8 @@ package com.beust.kobalt
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
-import com.beust.kobalt.api.ProjectDescription
import com.beust.kobalt.archive.Archives
import com.beust.kobalt.archive.Jar
-import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.*
import com.google.inject.Inject
@@ -93,26 +91,23 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
// If fatJar is true, add all the transitive dependencies as well: compile, runtime and dependent projects
//
if (jar.fatJar) {
- log(2, "Creating fat jar")
+ log(2, "Finding included files for fat jar")
val seen = hashSetOf()
@Suppress("UNCHECKED_CAST")
- val dependentProjects = project.projectProperties.get(JvmCompilerPlugin.DEPENDENT_PROJECTS)
- as List
val allDependencies = project.compileDependencies + project.compileRuntimeDependencies +
context.variant.buildType.compileDependencies +
context.variant.buildType.compileRuntimeDependencies +
context.variant.productFlavor.compileDependencies +
context.variant.productFlavor.compileRuntimeDependencies
- val transitiveDependencies = dependencyManager.calculateDependencies(project, context, dependentProjects,
- allDependencies)
+ val transitiveDependencies = dependencyManager.calculateDependencies(project, context, allDependencies)
transitiveDependencies.map {
it.jarFile.get()
}.forEach { file : File ->
if (! seen.contains(file.path)) {
seen.add(file.path)
if (! KFiles.Companion.isExcluded(file, jar.excludes)) {
- result.add(IncludedFile(specs = arrayListOf(IFileSpec.FileSpec(file.path)),
+ result.add(IncludedFile(specs = arrayListOf(IFileSpec.FileSpec(file.absolutePath)),
expandJarFiles = true))
}
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Plugins.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Plugins.kt
index c31837b0..29e902e1 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Plugins.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Plugins.kt
@@ -12,6 +12,7 @@ import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.log
import com.google.inject.Provider
+import java.io.File
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.net.URLClassLoader
@@ -78,7 +79,9 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider
+ taskManager.dynamicTasks.addAll(it.tasksFor(project, context))
+ }
}
// Now that we have collected all static and dynamic tasks, turn them all into plug-in tasks
@@ -160,9 +163,17 @@ class Plugins @Inject constructor (val taskManagerProvider : Provider = emptyList(),
vararg allDependencies: List): List
}
\ No newline at end of file
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ISourceDirectoriesInterceptor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ISourceDirectoriesInterceptor.kt
index aa39712b..33ec6e7c 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ISourceDirectoriesInterceptor.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ISourceDirectoriesInterceptor.kt
@@ -5,7 +5,7 @@ import java.io.File
/**
* Plug-ins can alter the source directories by implementing this interface.
*/
-interface ISourceDirectoryIncerceptor : IInterceptor {
+interface ISourceDirectoryInterceptor : IInterceptor {
fun intercept(project: Project, context: KobaltContext, sourceDirectories: List) : List
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ITaskContributor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ITaskContributor.kt
index 55eed61a..83621451 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ITaskContributor.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/ITaskContributor.kt
@@ -8,7 +8,7 @@ import com.beust.kobalt.internal.TaskResult2
* to implement this interface.
*/
interface ITaskContributor : IContributor {
- fun tasksFor(context: KobaltContext) : List
+ fun tasksFor(project: Project, context: KobaltContext) : List
}
class DynamicTask(override val plugin: IPlugin, override val name: String, override val doc: String,
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/Project.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/Project.kt
index a004071a..2e2b5146 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/Project.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/Project.kt
@@ -123,6 +123,8 @@ open class Project(
})
return result
}
+
+ override fun toString() = "[Project $name]"
}
class Sources(val project: Project, val sources: HashSet) {
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/TaskContributor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/TaskContributor.kt
index 7fa33775..65eb529d 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/TaskContributor.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/TaskContributor.kt
@@ -53,6 +53,7 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
runTask: (Project) -> IncrementalTaskInfo) {
Variant.allVariants(project).forEach { variant ->
val variantTaskName = variant.toTask(taskName)
+ context.variant = variant
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName, group, project,
dependsOn = dependsOn.map { variant.toTask(it) },
reverseDependsOn = reverseDependsOn.map { variant.toTask(it) },
@@ -62,5 +63,5 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
}
}
- override fun tasksFor(context: KobaltContext) : List = dynamicTasks
+ override fun tasksFor(project: Project, context: KobaltContext) : List = dynamicTasks
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt
index ca808318..66fe50e1 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/archive/Archives.kt
@@ -33,12 +33,19 @@ class Archives {
val result = File(archiveDir.path, fullArchiveName)
log(3, "Creating $result")
if (! Features.USE_TIMESTAMPS || isOutdated(project.directory, includedFiles, result)) {
- val outStream = outputStreamFactory(FileOutputStream(result))
- JarUtils.addFiles(project.directory, includedFiles, outStream, expandJarFiles)
- log(2, text = "Added ${includedFiles.size} files to $result")
- outStream.flush()
- outStream.close()
- log(1, " Created $result")
+ try {
+ outputStreamFactory(FileOutputStream(result)).use {
+ JarUtils.addFiles(project.directory, includedFiles, it, expandJarFiles)
+ log(2, text = "Added ${includedFiles.size} files to $result")
+ 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 {
log(3, " $result is up to date")
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/CompilerUtils.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/CompilerUtils.kt
new file mode 100644
index 00000000..fb551133
--- /dev/null
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/CompilerUtils.kt
@@ -0,0 +1,192 @@
+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.dependency.FileDependency
+import com.beust.kobalt.misc.KFiles
+import com.beust.kobalt.misc.log
+import com.google.inject.Inject
+import java.io.File
+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, val failedResult: TaskResult?)
+
+ fun invokeCompiler(project: Project, context: KobaltContext, compiler: ICompiler,
+ sourceDirectories: List, isTest: Boolean): CompilerResult {
+ val results = arrayListOf()
+ 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.size > 0) {
+ // TODO: createCompilerActionInfo recalculates the source files, only compute them
+ // once and pass them
+ val info = createCompilerActionInfo(project, context, compiler, isTest,
+ sourceDirectories, sourceSuffixes = compiler.sourceSuffixes)
+ val thisResult = invokeCompiler(project, context, compiler, info)
+ results.addAll(thisResult.successResults)
+ if (failedResult == null) {
+ failedResult = thisResult.failedResult
+ }
+ } else {
+ log(2, "Compiler $compiler not running on ${project.name} since no source files were found")
+ }
+
+ return CompilerResult(results, failedResult)
+ }
+
+ fun invokeCompiler(project: Project, context: KobaltContext, compiler: ICompiler, info: CompilerActionInfo)
+ : CompilerResult {
+ val results = arrayListOf()
+ 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: ICompiler,
+ isTest: Boolean, sourceDirectories: List, sourceSuffixes: List): CompilerActionInfo {
+ copyResources(project, context, SourceSet.of(isTest))
+
+ val fullClasspath = if (isTest) dependencyManager.testDependencies(project, context)
+ else dependencyManager.dependencies(project, context)
+
+ // The directory where the classes get compiled
+ val buildDirectory = if (isTest) File(project.buildDirectory, KFiles.TEST_CLASSES_DIR)
+ else File(project.classesDir(context))
+ File(project.directory, buildDirectory.path).mkdirs()
+
+ // Remove all the excluded dependencies from the classpath
+ var classpath = fullClasspath.filter {
+ ! isDependencyExcluded(it, project.excludedDependencies)
+ }
+
+ // 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.
+ if (buildDirectory.exists()) {
+ classpath += FileDependency(buildDirectory.path)
+ }
+
+ val initialSourceDirectories = ArrayList(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()
+ 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)
+ .map { File(it).canonicalPath }
+ .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
+ }
+
+ /**
+ * 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.size > 0) {
+ JvmCompilerPlugin.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 {
+ JvmCompilerPlugin.lp(project, "No resources to copy for $sourceSet")
+ }
+ }
+
+
+ /**
+ * 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)
+ = excluded.any { id.id.startsWith(it.id) }
+
+}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/IncrementalManager.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/IncrementalManager.kt
index bc53592e..f69e7107 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/IncrementalManager.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/IncrementalManager.kt
@@ -19,16 +19,17 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.util.*
-data class TaskInfo(val taskName: String, var inputChecksum: String? = null, var outputChecksum: String? = null)
-
-class BuildInfo(var tasks: List)
-
/**
* Manage the file .kobalt/buildInfo.json, which keeps track of input and output checksums to manage
* incremental builds.
*/
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)
+
interface IFactory {
fun create(@Assisted fileName: String = IncrementalManager.BUILD_INFO_FILE) : IncrementalManager
}
@@ -79,6 +80,7 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
fun outputChecksumFor(taskName: String) : String? =
taskInfoFor(taskInfos(), taskName).outputChecksum
+
/**
* @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
@@ -93,7 +95,8 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
var upToDate = false
var taskOutputChecksum : String? = null
- if (args.noIncremental || (Kobalt.context?.internalContext?.buildFileOutOfDate as Boolean)) {
+ if (! args.forceIncremental &&
+ (args.noIncremental || (Kobalt.context?.internalContext?.buildFileOutOfDate as Boolean))) {
//
// If the user turned off incremental builds or if the build file was modified, always run this task
//
@@ -124,7 +127,8 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
if (outputChecksum == taskOutputChecksum) {
upToDate = true
} else {
- logIncremental(LEVEL, "Incremental task $taskName output is out of date, running it")
+ logIncremental(LEVEL, "Incremental task $taskName output is out of date" +
+ " (different output checksums), running it")
}
}
} else {
@@ -132,7 +136,7 @@ class IncrementalManager @Inject constructor(val args: Args, @Assisted val fileN
logIncremental(LEVEL, "Project ${project.name} depends on dirty project, running $taskName")
} else {
logIncremental(LEVEL, "Incremental task $taskName input is out of date, running it"
- + " old: $inputChecksum new: ${iti.inputChecksum()}")
+ + " (different input checksums old: $inputChecksum new: ${iti.inputChecksum()})")
}
project.projectExtra.isDirty = true
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt
index 41de8408..7dbde4c4 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt
@@ -30,7 +30,8 @@ open class JvmCompilerPlugin @Inject constructor(
open val files: KFiles,
open val dependencyManager: DependencyManager,
open val executors: KobaltExecutors,
- open val taskContributor : TaskContributor)
+ open val taskContributor : TaskContributor,
+ val compilerUtils: CompilerUtils)
: BasePlugin(), ISourceDirectoryContributor, IProjectContributor, ITaskContributor by taskContributor {
companion object {
@@ -52,19 +53,19 @@ open class JvmCompilerPlugin @Inject constructor(
const val GROUP_TEST = "test"
const val GROUP_BUILD = "build"
const val GROUP_DOCUMENTATION = "documentation"
+
+ /**
+ * Log with a project.
+ */
+ fun lp(project: Project, s: String) {
+ log(2, "${project.name}: $s")
+ }
}
override val name: String = PLUGIN_NAME
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) {
super.apply(project, context)
// cleanUpActors()
@@ -112,41 +113,9 @@ open class JvmCompilerPlugin @Inject constructor(
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 {
- val result = project.projectProperties.get(COMPILER_ARGS)
- if (result != null) {
- @Suppress("UNCHECKED_CAST")
- return result as List
- } else {
- return emptyList()
- }
- }
-
@IncrementalTask(name = TASK_COMPILE_TEST, description = "Compile the tests", group = GROUP_BUILD,
dependsOn = arrayOf(TASK_COMPILE))
fun taskCompileTest(project: Project): IncrementalTaskInfo {
- sourceTestDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = true)))
return IncrementalTaskInfo(
inputChecksum = {
Md5.toMd5Directories(context.testSourceDirectories(project).map { File(project.directory, it.path)})
@@ -159,12 +128,12 @@ open class JvmCompilerPlugin @Inject constructor(
)
}
+ private fun sourceDirectories(project: Project, context: KobaltContext)
+ = context.variant.sourceDirectories(project, context, SourceSet.of(isTest = false))
+
@IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project", group = GROUP_BUILD,
runAfter = arrayOf(TASK_CLEAN))
fun taskCompile(project: Project): IncrementalTaskInfo {
- // Set up the source files now that we have the variant
- sourceDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = false)))
-
return IncrementalTaskInfo(
inputChecksum = {
Md5.toMd5Directories(context.sourceDirectories(project).map { File(project.directory, it.path) })
@@ -193,29 +162,32 @@ open class JvmCompilerPlugin @Inject constructor(
throw KobaltException("Couldn't find any compiler for project ${project.name}")
} else {
val allCompilers = compilerContributors.flatMap { it.compilersFor(project, context)}.sorted()
- allCompilers.forEach { compiler ->
- 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.size > 0) {
- // TODO: createCompilerActionInfo recalculates the source files, only compute them
- // once and pass them
- val info = createCompilerActionInfo(project, context, compiler, isTest, sourceDirectories,
- 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")
+
+ /**
+ * Swap the Java and Kotlin compilers from the list.
+ */
+ fun swapJavaAndKotlin(allCompilers: List): List {
+ val result = ArrayList(allCompilers)
+ 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
}
+ 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 finalAllCompilers = if (hasKapt) swapJavaAndKotlin(allCompilers) else allCompilers
+ finalAllCompilers.forEach { compiler ->
+ val compilerResults = compilerUtils.invokeCompiler(project, context, compiler,
+ sourceDirectories(project, context), isTest)
+ results.addAll(compilerResults.successResults)
+ if (failedResult == null) failedResult = compilerResults.failedResult
+ }
+
return if (failedResult != null) failedResult!!
else if (results.size > 0) results[0]
else TaskResult(true)
@@ -249,9 +221,9 @@ open class JvmCompilerPlugin @Inject constructor(
var result: TaskResult? = null
contributors.forEach {
it.compilersFor(project, context).forEach { compiler ->
- result = docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context,
- compiler,
- isTest = false, sourceDirectories = sourceDirectories,
+ result = docGenerator.generateDoc(project, context,
+ compilerUtils.createCompilerActionInfo(project, context, compiler,
+ isTest = false, sourceDirectories = sourceDirectories(project, context),
sourceSuffixes = compiler.sourceSuffixes))
}
}
@@ -262,110 +234,10 @@ 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)
- = 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, sourceSuffixes: List): 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(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()
- 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
- }
-
- val sourceDirectories = arrayListOf()
- val sourceTestDirectories = arrayListOf()
-
// ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext)
= if (accept(project)) {
- sourceDirectories.toList()
+ sourceDirectories(project, context)
} else {
arrayListOf()
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt
index 4df2409b..33c0176e 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt
@@ -76,8 +76,8 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
val repoContributors = arrayListOf()
val compilerFlagContributors = arrayListOf()
val compilerInterceptors = arrayListOf()
- val sourceDirectoriesInterceptors = arrayListOf()
- val buildDirectoryInterceptors = arrayListOf()
+ val sourceDirectoriesInterceptors = arrayListOf()
+ val buildDirectoryInterceptors = arrayListOf()
val runnerContributors = arrayListOf()
val testRunnerContributors = arrayListOf()
val classpathInterceptors = arrayListOf()
@@ -156,10 +156,22 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
GuiceFactory()
}
- fun forName(className: String) =
- if (pluginClassLoader != null) pluginClassLoader.loadClass(className)
- else if (classLoader != null) classLoader.loadClass(className)
- else Class.forName(className)
+ fun forName(className: String) : Class<*> {
+ fun loadClass(className: String, classLoader: ClassLoader?) : Class<*>? {
+ try {
+ return classLoader?.loadClass(className)
+ } catch(ex: ClassNotFoundException) {
+ return null
+ }
+ }
+
+ val result = loadClass(className, classLoader)
+ ?: Class.forName(className)
+ ?: loadClass(className, pluginClassLoader)
+ ?: throw ClassNotFoundException(className)
+
+ return result
+ }
//
// Populate pluginInfo with what was found in Kobalt's own kobalt-plugin.xml
@@ -169,7 +181,7 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
with(factory.instanceOf(forName(it))) {
// Note: can't use "when" here since the same instance can implement multiple interfaces
if (this is IBuildConfigFieldContributor) buildConfigFieldContributors.add(this)
- if (this is IBuildDirectoryIncerceptor) buildDirectoryInterceptors.add(this)
+ if (this is IBuildDirectoryInterceptor) buildDirectoryInterceptors.add(this)
if (this is IClasspathContributor) classpathContributors.add(this)
if (this is IClasspathInterceptor) classpathInterceptors.add(this)
if (this is ICompilerContributor) compilerContributors.add(this)
@@ -182,7 +194,7 @@ class PluginInfo(val xml: KobaltPluginXml, val pluginClassLoader: ClassLoader?,
if (this is IRepoContributor) repoContributors.add(this)
if (this is IRunnerContributor) runnerContributors.add(this)
if (this is ISourceDirectoryContributor) sourceDirContributors.add(this)
- if (this is ISourceDirectoryIncerceptor) sourceDirectoriesInterceptors.add(this)
+ if (this is ISourceDirectoryInterceptor) sourceDirectoriesInterceptors.add(this)
if (this is ITaskContributor) taskContributors.add(this)
if (this is ITestRunnerContributor) testRunnerContributors.add(this)
if (this is IMavenIdInterceptor) mavenIdInterceptors.add(this)
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltSettingsXml.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltSettingsXml.kt
index b803393e..fe9ffc41 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltSettingsXml.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KobaltSettingsXml.kt
@@ -27,7 +27,7 @@ class KobaltSettingsXml {
var proxies: ProxiesXml? = null
@XmlElement(name = "kobalt-compiler-version") @JvmField
- var kobaltCompilerVersion: String = "1.0.0"
+ var kobaltCompilerVersion: String = "1.0.2"
@XmlElement(name = "kobalt-compiler-repo") @JvmField
var kobaltCompilerRepo: String? = null
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt
new file mode 100644
index 00000000..3f29427a
--- /dev/null
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/KotlinJarFiles.kt
@@ -0,0 +1,21 @@
+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 runtime: File get() = getKotlinCompilerJar("runtime")
+ val compiler: File get() = getKotlinCompilerJar("compiler-embeddable")
+}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt
index 2039c9e1..6d8e478c 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt
@@ -4,10 +4,7 @@ import com.beust.kobalt.*
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task
-import com.beust.kobalt.misc.Strings
-import com.beust.kobalt.misc.benchmarkMillis
-import com.beust.kobalt.misc.kobaltError
-import com.beust.kobalt.misc.log
+import com.beust.kobalt.misc.*
import com.google.common.annotations.VisibleForTesting
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.ListMultimap
@@ -81,7 +78,41 @@ class TaskManager @Inject constructor(val args: Args,
}
}
- fun runTargets(taskNames: List, projects: List): RunTargetResult {
+ fun runTargets(passedTaskNames: List, allProjects: List): RunTargetResult {
+ val taskInfos = calculateDependentTaskNames(passedTaskNames, allProjects)
+ val projectsToRun = findProjectsToRun(taskInfos, allProjects)
+ return runProjects(taskInfos, projectsToRun)
+ }
+
+ /**
+ * Determine which projects to run based on the request tasks. Also make sure that all the requested projects
+ * exist.
+ */
+ fun findProjectsToRun(taskInfos: List, projects: List) : List {
+
+ // Validate projects
+ val result = arrayListOf()
+ val projectMap = HashMap().apply {
+ projects.forEach { put(it.name, it)}
+ }
+
+ // Extract all the projects we need to run from the tasks
+// val orderedTaskInfos = calculateDependentTaskNames(taskInfos.map { it.id }, projects)
+ taskInfos.forEach {
+ val p = it.project
+ if (p != null) {
+ if (! 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 else projects
+ }
+
+ private fun runProjects(taskInfos: List, projects: List) : RunTargetResult {
var result = 0
val failedProjects = hashSetOf()
val messages = Collections.synchronizedList(arrayListOf())
@@ -111,7 +142,7 @@ class TaskManager @Inject constructor(val args: Args,
log(3, " $it: " + tasksByNames.get(it))
}
- val graph = createGraph2(project.name, taskNames, tasksByNames,
+ val graph = createGraph2(project.name, taskInfos, tasksByNames,
dependsOn, reverseDependsOn, runBefore, runAfter, alwaysRunAfter,
{ task: ITask -> task.name },
{ task: ITask -> task.plugin.accept(project) })
@@ -137,9 +168,65 @@ class TaskManager @Inject constructor(val args: Args,
}
}
}
+
return RunTargetResult(result, messages)
}
+ /**
+ * 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, invoke these tasks on all of them. This
+ * function returns all these task names (including dependent).
+ */
+ fun calculateDependentTaskNames(taskNames: List, projects: List): List {
+ val projectMap = hashMapOf().apply {
+ projects.forEach { project -> put(project.name, project)}
+ }
+
+ val allTaskInfos = HashSet(taskNames.map { TaskInfo(it) })
+ with(Topological()) {
+ val toProcess = ArrayList(allTaskInfos)
+ val seen = HashSet(allTaskInfos)
+ val newTasks = hashSetOf()
+
+ fun maybeAdd(taskInfo: TaskInfo) {
+ if (!seen.contains(taskInfo)) {
+ newTasks.add(taskInfo)
+ seen.add(taskInfo)
+ }
+ }
+
+ while (toProcess.any()) {
+ toProcess.forEach { ti ->
+ val project = projectMap[ti.project]
+ if (project != null) {
+ val dependents = project.projectExtra.dependsOn
+ if (dependents.any()) {
+ dependents.forEach { depProject ->
+ val tiDep = TaskInfo(depProject.name, ti.taskName)
+ allTaskInfos.add(tiDep)
+ addEdge(ti, tiDep)
+ maybeAdd(tiDep)
+ }
+ } else {
+ allTaskInfos.add(ti)
+ addNode(ti)
+ }
+ } else {
+ // No project specified for this task, run that task in all the projects
+ projects.forEach {
+ maybeAdd(TaskInfo(it.name, ti.taskName))
+ }
+ }
+ }
+ toProcess.clear()
+ toProcess.addAll(newTasks)
+ newTasks.clear()
+ }
+ val result = sort()
+ return result
+ }
+ }
+
val LOG_LEVEL = 3
/**
@@ -150,7 +237,8 @@ class TaskManager @Inject constructor(val args: Args,
* we'll be adding to the graph while @toName extracts the name of a node.
*/
@VisibleForTesting
- fun createGraph2(projectName: String, taskNames: List, nodeMap: Multimap,
+ fun createGraph2(projectName: String, passedTasks: List,
+ nodeMap: Multimap,
dependsOn: Multimap,
reverseDependsOn: Multimap,
runBefore: Multimap,
@@ -176,9 +264,9 @@ class TaskManager @Inject constructor(val args: Args,
}
//
- // Turn the task names into the more useful TaskInfo and do some sanity checking on the way
+ // Keep only the tasks we need to run.
//
- val taskInfos = taskNames.map { TaskInfo(it) }.filter {
+ val taskInfos = passedTasks.filter {
if (!nodeMap.keys().contains(it.taskName)) {
throw KobaltException("Unknown task: $it")
}
@@ -262,14 +350,16 @@ class TaskManager @Inject constructor(val args: Args,
// 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")
+ passedTasks.map { it.id }.let { taskNames ->
+ 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")
+ runAfter[taskName].forEach { to ->
+ if (taskNames.contains(to)) {
+ addEdge(result, taskName, to, newToProcess, "runAfter")
+ }
}
}
seen.add(taskName)
@@ -339,16 +429,14 @@ class TaskManager @Inject constructor(val args: Args,
*/
fun computePluginTasks(projects: List) {
installAnnotationTasks(projects)
- installDynamicTasks(projects)
+ installDynamicTasks()
}
- private fun installDynamicTasks(projects: List) {
+ private fun installDynamicTasks() {
dynamicTasks.forEach { task ->
- projects.filter { task.plugin.accept(it) }.forEach { project ->
- addTask(task.plugin, project, task.name, task.doc, task.group,
- task.dependsOn, task.reverseDependsOn, task.runBefore, task.runAfter, task.alwaysRunAfter,
- task.closure)
- }
+ addTask(task.plugin, task.project, task.name, task.doc, task.group,
+ task.dependsOn, task.reverseDependsOn, task.runBefore, task.runAfter, task.alwaysRunAfter,
+ task.closure)
}
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt
index 93d997ed..93d4c705 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt
@@ -85,14 +85,13 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* allDependencies is typically either compileDependencies or testDependencies
*/
override fun calculateDependencies(project: Project?, context: KobaltContext,
- dependentProjects: List,
vararg allDependencies: List): List {
val result = arrayListOf()
allDependencies.forEach { dependencies ->
result.addAll(transitiveClosure(dependencies))
}
result.addAll(runClasspathContributors(project, context))
- result.addAll(dependentProjectDependencies(dependentProjects, project, context))
+ result.addAll(dependentProjectDependencies(project, context))
return result
}
@@ -112,9 +111,9 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
*/
fun transitiveClosure(dependencies : List, indent : String = " "):
List {
- var executor = executors.newExecutor("JvmCompiler}", 10)
+ val executor = executors.newExecutor("JvmCompiler}", 10)
- var result = hashSetOf()
+ val result = hashSetOf()
dependencies.forEach { projectDependency ->
log(ConsoleRepositoryListener.LOG_LEVEL, "$indent Resolving $projectDependency")
@@ -169,27 +168,25 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* If this project depends on other projects, we need to include their jar file and also
* their own dependencies
*/
- private fun dependentProjectDependencies(projectDescriptions: List,
+ private fun dependentProjectDependencies(
project: Project?, context: KobaltContext) : List {
- val result = arrayListOf()
- projectDescriptions.filter {
- it.project.name == project?.name
- }.forEach { pd ->
- pd.dependsOn.forEach { p ->
+ if (project == null) {
+ return emptyList()
+ } else {
+ val result = arrayListOf()
+ project.projectExtra.dependsOn.forEach { p ->
result.add(FileDependency(KFiles.joinDir(p.directory, p.classesDir(context))))
- val otherDependencies = calculateDependencies(p, context, projectDescriptions,
- p.compileDependencies)
+ val otherDependencies = calculateDependencies(p, context, p.compileDependencies)
result.addAll(otherDependencies)
- }
- }
- return result
+ }
+ return result
+ }
}
private fun dependencies(project: Project, context: KobaltContext, isTest: Boolean)
: List {
val transitive = hashSetOf()
- val projects = listOf(ProjectDescription(project, project.projectExtra.dependsOn))
with(project) {
val deps = arrayListOf(compileDependencies, compileProvidedDependencies,
context.variant.buildType.compileDependencies,
@@ -202,15 +199,20 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
deps.add(testProvidedDependencies)
}
deps.filter { it.any() }.forEach {
- transitive.addAll(calculateDependencies(project, context, projects, it))
+ transitive.addAll(calculateDependencies(project, context, it))
}
}
// Make sure that classes/ and test-classes/ are always at the top of this classpath,
// so that older versions of that project on the classpath don't shadow them
- val result = listOf(FileDependency(KFiles.makeOutputDir(project).absolutePath),
- FileDependency(KFiles.makeOutputTestDir(project).absolutePath)) +
- reorderDependencies(transitive)
+ val result = arrayListOf().apply {
+ if (isTest) {
+ add(FileDependency(KFiles.makeOutputDir(project).absolutePath))
+ add(FileDependency(KFiles.makeOutputTestDir(project).absolutePath))
+ }
+ addAll(reorderDependencies(transitive))
+ }
+
return result
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Md5.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Md5.kt
index 339efaa1..6ed088a4 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Md5.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Md5.kt
@@ -18,12 +18,18 @@ public class Md5 {
// return DatatypeConverter.printHexBinary(md5.digest()).toLowerCase()
// }
- fun toMd5Directories(directories: List) : String? {
- val ds = directories.filter { it.exists() }
+ /**
+ * Calculate a checksum for all the files/directories. The conversion from File to
+ * bytes can be customized by the @param{toBytes} parameter. The default implementation calculates
+ * a checksum of the last modified timestamp.
+ */
+ fun toMd5Directories(filesOrDirectories: List,
+ toBytes: (File) -> ByteArray = { it.lastModified().toString().toByteArray() } ): String? {
+ val ds = filesOrDirectories.filter { it.exists() }
if (ds.size > 0) {
MessageDigest.getInstance("MD5").let { md5 ->
var fileCount = 0
- directories.filter { it.exists() }.forEach { file ->
+ filesOrDirectories.filter { it.exists() }.forEach { file ->
if (file.isFile) {
val bytes = file.readBytes()
md5.update(bytes, 0, bytes.size)
@@ -37,7 +43,7 @@ public class Md5 {
it.isFile
}.forEach {
fileCount++
- val bytes = it.readBytes()
+ val bytes = toBytes(it)
md5.update(bytes, 0, bytes.size)
}
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Pom.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Pom.kt
index 48f6965e..a6263e22 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Pom.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/maven/Pom.kt
@@ -3,11 +3,9 @@ package com.beust.kobalt.maven
import com.beust.kobalt.misc.toString
import com.beust.kobalt.misc.warn
import com.google.inject.assistedinject.Assisted
-import kotlinx.dom.childElements
import org.w3c.dom.Element
import org.w3c.dom.NodeList
-import org.xml.sax.InputSource
-import java.io.FileReader
+import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathConstants
class Pom @javax.inject.Inject constructor(@Assisted val id: String,
@@ -66,8 +64,8 @@ class Pom @javax.inject.Inject constructor(@Assisted val id: String,
init {
val DEPENDENCIES = XPATH.compile("/project/dependencies/dependency")
+ val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(documentFile)
- val document = kotlinx.dom.parseXml(InputSource(FileReader(documentFile)))
groupId = XPATH.compile("/project/groupId").evaluate(document)
artifactId = XPATH.compile("/project/artifactId").evaluate(document)
version = XPATH.compile("/project/version").evaluate(document)
@@ -75,11 +73,12 @@ class Pom @javax.inject.Inject constructor(@Assisted val id: String,
var repositoriesList = XPATH.compile("/project/repositories").evaluate(document, XPathConstants.NODESET)
as NodeList
var repoElem = repositoriesList.item(0) as Element?
- repositories = repoElem.childElements().map({ it.getElementsByTagName("url").item(0).textContent })
+ repositories = childElements(repoElem).map({ it.getElementsByTagName("url").item(0)
+ .textContent })
val propertiesList = XPATH.compile("/project/properties").evaluate(document, XPathConstants.NODESET) as NodeList
var propsElem = propertiesList.item(0) as Element?
- propsElem.childElements().forEach {
+ childElements(propsElem).forEach {
properties.put(it.nodeName, it.textContent)
}
@@ -111,5 +110,18 @@ class Pom @javax.inject.Inject constructor(@Assisted val id: String,
}
}
+ private fun childElements(repoElem: Element?): List {
+ val result = arrayListOf()
+ if (repoElem != null) {
+ for (i in 0..repoElem.childNodes.length - 1) {
+ val elem = repoElem.childNodes.item(i)
+ if (elem is Element) {
+ result.add(elem)
+ }
+ }
+ }
+ return result
+ }
+
override fun toString() = toString("Pom", "id", id)
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Io.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Io.kt
index 6f8694a9..a354043e 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Io.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Io.kt
@@ -73,7 +73,7 @@ class Io(val dryRun: Boolean = false) {
}
fun mkdir(dir: File) {
- log("rm -rf $dir")
+ log("mkdir $dir")
if (! dryRun) {
dir.mkdirs()
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/JarUtils.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/JarUtils.kt
index 90b8aacc..a17c2196 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/JarUtils.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/JarUtils.kt
@@ -9,7 +9,6 @@ import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarInputStream
import java.util.zip.ZipEntry
-import java.util.zip.ZipException
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
@@ -48,27 +47,14 @@ public class JarUtils {
}
if (foundFile.isDirectory) {
- log(2, "Writing contents of directory $foundFile")
+ log(2, " Writing contents of directory $foundFile")
// Directory
- var name = foundFile.name
- if (!name.isEmpty()) {
- if (!name.endsWith("/")) name += "/"
- val entry = JarEntry(name)
- entry.time = foundFile.lastModified()
- try {
- outputStream.putNextEntry(entry)
- } catch(ex: ZipException) {
- log(2, "Can't add $name: ${ex.message}")
- } finally {
- outputStream.closeEntry()
- }
- }
- val includedFile = IncludedFile(From(foundFile.path), To(""), listOf(IFileSpec.GlobSpec("**")))
- addSingleFile(".", includedFile, outputStream, expandJarFiles)
+ val includedFile = IncludedFile(From(""), To(""), listOf(IFileSpec.GlobSpec("**")))
+ addSingleFile(localFile.path, includedFile, outputStream, expandJarFiles)
} else {
if (file.expandJarFiles && foundFile.name.endsWith(".jar") && ! file.from.contains("resources")) {
- log(2, "Writing contents of jar file $foundFile")
+ log(2, " Writing contents of jar file $foundFile")
val stream = JarInputStream(FileInputStream(localFile))
var entry = stream.nextEntry
while (entry != null) {
@@ -81,7 +67,7 @@ public class JarUtils {
} else {
val entryFileName = file.to(foundFile.path).path.replace("\\", "/")
val entry = JarEntry(entryFileName)
- entry.time = foundFile.lastModified()
+ entry.time = localFile.lastModified()
addEntry(FileInputStream(localFile), entry, outputStream, onError)
}
}
diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Topological.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Topological.kt
index b0a92315..38c4c503 100644
--- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Topological.kt
+++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/Topological.kt
@@ -10,22 +10,25 @@ import java.util.*
*/
class Topological {
private val dependingOn = ArrayListMultimap.create()
+ private val nodes = hashSetOf()
+
+ fun addNode(t: T) = nodes.add(t)
fun addEdge(t: T, other: T) {
+ addNode(t)
+ addNode(other)
dependingOn.put(t, other)
}
- fun addEdge(t: T, others: Array) {
- dependingOn.putAll(t, others.toMutableList())
- }
-
/**
* @return the Ts sorted topologically.
*/
- fun sort(all: ArrayList) : List {
+ fun sort() : List {
+ val all = ArrayList(nodes)
val result = arrayListOf()
var dependMap = HashMultimap.create()
dependingOn.keySet().forEach { dependMap.putAll(it, dependingOn.get(it))}
+ nodes.forEach { dependMap.putAll(it, emptyList())}
while (all.size > 0) {
val freeNodes = all.filter {
dependMap.get(it).isEmpty()
diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt
index 576ec211..6222b686 100644
--- a/src/main/kotlin/com/beust/kobalt/Main.kt
+++ b/src/main/kotlin/com/beust/kobalt/Main.kt
@@ -115,7 +115,7 @@ private class Main @Inject constructor(
val seconds = benchmarkSeconds {
try {
result = runWithArgs(jc, args, argv, pluginClassLoader)
- } catch(ex: KobaltException) {
+ } catch(ex: Throwable) {
error("", ex.cause ?: ex)
result = 1
}
diff --git a/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt b/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt
index fbeaef40..a077a9e6 100644
--- a/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt
+++ b/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt
@@ -20,7 +20,6 @@ import java.io.InputStream
import java.lang.reflect.Modifier
import java.net.URL
import java.net.URLClassLoader
-import java.util.*
import java.util.jar.JarInputStream
class BuildScriptUtil @Inject constructor(val plugins: Plugins, val files: KFiles,
@@ -113,14 +112,14 @@ class BuildScriptUtil @Inject constructor(val plugins: Plugins, val files: KFile
context.pluginInfo.projectContributors.forEach { contributor ->
val descriptions = contributor.projects()
descriptions.forEach { pd ->
- all.add(pd.project)
+ topologicalProjects.addNode(pd.project)
pd.dependsOn.forEach { dependsOn ->
topologicalProjects.addEdge(pd.project, dependsOn)
all.add(dependsOn)
}
}
}
- val result = topologicalProjects.sort(ArrayList(all))
+ val result = topologicalProjects.sort()
return result
}
diff --git a/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt b/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt
index a47a4d1a..403c8f5c 100644
--- a/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt
+++ b/src/main/kotlin/com/beust/kobalt/app/LanguageTemplateGenerator.kt
@@ -3,7 +3,6 @@ package com.beust.kobalt.app
import com.beust.kobalt.Args
import com.beust.kobalt.api.ITemplate
import com.beust.kobalt.api.ITemplateContributor
-import com.beust.kobalt.app.Mustache
import com.beust.kobalt.maven.Pom
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
@@ -85,7 +84,7 @@ abstract class LanguageTemplateGenerator : ITemplate {
private fun importPom(pomFile: File, mainDeps: ArrayList, testDeps: ArrayList,
map: HashMap) {
- var pom = Pom("imported", pomFile.absoluteFile)
+ val pom = Pom("imported", pomFile.absoluteFile)
with(map) {
put("group", pom.groupId ?: PACKAGE_NAME)
put("artifactId", pom.artifactId ?: PACKAGE_NAME)
diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/DependencyData.kt b/src/main/kotlin/com/beust/kobalt/app/remote/DependencyData.kt
index 7a4f4eec..7f612aa9 100644
--- a/src/main/kotlin/com/beust/kobalt/app/remote/DependencyData.kt
+++ b/src/main/kotlin/com/beust/kobalt/app/remote/DependencyData.kt
@@ -36,6 +36,8 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
val pluginDependencies = projectResult.pluginUrls.map { File(it.toURI()) }.map {
FileDependency(it.absolutePath)
}
+
+ val allTasks = hashSetOf()
projectResult.projects.forEach { project ->
val compileDependencies = pluginDependencies.map { toDependencyData(it, "compile") } +
allDeps(project.compileDependencies).map { toDependencyData(it, "compile") } +
@@ -55,15 +57,16 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
// Separate resource from source directories
val sources = project.sourceDirectories.partition { KFiles.isResource(it) }
val tests = project.sourceDirectoriesTest.partition { KFiles.isResource(it) }
- val allTasks = taskManager.tasksByNames(project).values().map {
+ val projectTasks = taskManager.tasksByNames(project).values().map {
TaskData(it.name, it.doc, it.group)
}
+ allTasks.addAll(projectTasks)
projectDatas.add(ProjectData(project.name, project.directory, dependentProjects,
compileDependencies, testDependencies,
sources.second.toSet(), tests.second.toSet(), sources.first.toSet(), tests.first.toSet(),
- allTasks))
+ projectTasks))
}
- return GetDependenciesData(projectDatas, projectResult.taskResult.errorMessage)
+ return GetDependenciesData(projectDatas, allTasks, projectResult.taskResult.errorMessage)
}
/////
@@ -72,7 +75,9 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
//
class DependencyData(val id: String, val scope: String, val path: String)
- class TaskData(val name: String, val description: String, val group: String)
+ data class TaskData(val name: String, val description: String, val group: String) {
+ override fun toString() = name
+ }
class ProjectData(val name: String, val directory: String,
val dependentProjects: List,
@@ -81,5 +86,7 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
val sourceResourceDirs: Set, val testResourceDirs: Set,
val tasks: Collection)
- class GetDependenciesData(val projects: List, val errorMessage: String?)
+ class GetDependenciesData(val projects: List = emptyList(),
+ val allTasks: Collection = emptySet(),
+ val errorMessage: String?)
}
diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt
index 2b0cb10b..237c0ccb 100644
--- a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt
+++ b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltClient.kt
@@ -17,6 +17,7 @@ import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
import java.io.*
@@ -31,7 +32,10 @@ fun main(argv: Array) {
}
interface Api {
- @POST("/getDependencies")
+ @GET("/ping")
+ fun ping() : Call
+
+ @POST("/v0/getDependencies")
fun getDependencies(@Query("buildFile") buildFile: String) : Call>
}
@@ -40,16 +44,25 @@ class KobaltClient : Runnable {
private val service = Retrofit.Builder()
.client(OkHttpClient.Builder().build())
- .baseUrl("http://localhost:1252")
+ .baseUrl("http://localhost:1238")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Api::class.java)
override fun run() {
+
+// val pong = service.ping().execute()
+// println("Result from ping: " + pong)
+
val buildFile = Paths.get(SystemProperties.homeDir, "kotlin/klaxon/kobalt/src/Build.kt").toString()
val dependencies = service.getDependencies(buildFile)
- val results = dependencies.execute()
- println("Dependencies: $results")
+ val response = dependencies.execute()
+ if (response.isSuccessful) {
+ println("Dependencies: $response")
+ } else {
+ println("Error calling getDependencies: " + response.errorBody().string())
+ }
+ println("")
}
}
diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt
index 71e34391..7913852b 100644
--- a/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt
+++ b/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt
@@ -36,7 +36,7 @@ class SparkServer(val initCallback: (String) -> List, val cleanUpCallba
override fun run(port: Int) {
Spark.port(port)
- Spark.get("/ping", { req, res -> KobaltServer.OK })
+ Spark.get("/ping", { req, res -> """ { "result" : "ok" } """ })
Spark.get("/quit", { req, res ->
Executors.newFixedThreadPool(1).let { executor ->
executor.submit {
@@ -58,13 +58,13 @@ class SparkServer(val initCallback: (String) -> List, val cleanUpCallba
dependencyData.dependenciesDataFor(buildFile, args)
} catch(ex: Exception) {
- DependencyData.GetDependenciesData(emptyList(), ex.message)
+ DependencyData.GetDependenciesData(errorMessage = ex.message)
} finally {
cleanUpCallback()
}
} else {
- DependencyData.GetDependenciesData(emptyList(),
- "buildFile wasn't passed in the query parameter")
+ DependencyData.GetDependenciesData(
+ errorMessage = "buildFile wasn't passed in the query parameter")
}
cleanUpCallback()
result
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt
index 3b871016..483a9f3f 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt
@@ -7,12 +7,11 @@ import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.archive.Archives
import com.beust.kobalt.archive.Jar
import com.beust.kobalt.internal.ActorUtils
-import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.RunCommand
-import com.beust.kobalt.misc.warn
+import com.beust.kobalt.misc.log
import com.beust.kobalt.plugin.packaging.PackageConfig
import com.beust.kobalt.plugin.packaging.PackagingPlugin
import com.google.inject.Inject
@@ -60,7 +59,7 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor 0) {
return runContributor.run(project, context, dependencyManager.dependencies(project, context))
} else {
- warn("Couldn't find a runner for project ${project.name}. Please make sure your build file contains " +
+ log(2, "Couldn't find a runner for project ${project.name}. Please make sure your build file contains " +
"an application{} directive with a mainClass=... in it")
return TaskResult()
}
@@ -106,12 +105,10 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor
// If the jar file is not fat, we need to add the transitive closure of all dependencies
// on the classpath
val allTheDependencies =
- dependencyManager.calculateDependencies(project, context, projDeps,
+ dependencyManager.calculateDependencies(project, context,
allDependencies = project.compileDependencies).map { it.jarFile.get().path }
allDeps.addAll(allTheDependencies)
}
@@ -130,6 +127,6 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor = taskContributor.dynamicTasks
+ override fun tasksFor(project: Project, context: KobaltContext): List = taskContributor.dynamicTasks
}
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/apt/AptPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/apt/AptPlugin.kt
index 4c7f5e7c..0aede4b9 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/apt/AptPlugin.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/apt/AptPlugin.kt
@@ -2,12 +2,16 @@ package com.beust.kobalt.plugin.apt
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.Directive
+import com.beust.kobalt.internal.ActorUtils
+import com.beust.kobalt.internal.CompilerUtils
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
import com.google.common.collect.ArrayListMultimap
import com.google.inject.Inject
import java.io.File
+import java.nio.file.Files
+import java.util.*
import javax.inject.Singleton
/**
@@ -18,30 +22,82 @@ import javax.inject.Singleton
* (outputDir, etc...).
*/
@Singleton
-class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, val configActor: ConfigActor)
- : BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor, IConfigActor by configActor {
+class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, val compilerUtils: CompilerUtils)
+ : BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor, ITaskContributor {
// ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List {
- val config = configurationFor(project)
- val result =
- if (config != null) {
- listOf(File(
- KFiles.joinDir(KFiles.KOBALT_BUILD_DIR, config.outputDir, context.variant.toIntermediateDir())))
- } else {
- emptyList()
- }
+ val result = arrayListOf()
+ aptConfigs[project.name]?.let { config ->
+ result.add(File(
+ KFiles.joinDir(project.directory,
+ KFiles.KOBALT_BUILD_DIR,
+ config.outputDir)))
+ }
+
+ kaptConfigs[project.name]?.let { config ->
+ result.add(File(
+ KFiles.joinDir(project.directory,
+ KFiles.KOBALT_BUILD_DIR,
+ config.outputDir)))
+ }
return result
}
companion object {
const val PLUGIN_NAME = "Apt"
+ const val KAPT_CONFIG = "kaptConfig"
+ const val APT_CONFIG = "aptConfig"
}
override val name = PLUGIN_NAME
+ override fun apply(project: Project, context: KobaltContext) {
+ }
+
+ // ITaskContributor
+ override fun tasksFor(project: Project, context: KobaltContext) : List {
+// val kapt = kaptConfigs[project.name]
+// if (kapt != null) {
+// return listOf(DynamicTask(this, "kapt", "Run kapt", project = project,
+// reverseDependsOn = listOf(JvmCompilerPlugin.TASK_COMPILE),
+// group = AnnotationDefault.GROUP,
+// closure = { project ->
+// runApt(project, context)
+// TaskResult()
+// }))
+// } else {
+ return emptyList()
+// }
+//
+ }
+
+ private fun runApt(project: Project, context: KobaltContext) {
+ val kapt = kaptConfigs[project.name]
+ if (kapt != null) {
+
+ val sourceDir = Files.createTempDirectory("kobalt").toFile()
+ val javaFile = File(sourceDir, "A.java").apply {
+ appendText("class A {}")
+ }
+ val compilerContributors = context.pluginInfo.compilerContributors
+ ActorUtils.selectAffinityActors(project, context,
+ context.pluginInfo.compilerContributors)
+
+ val allCompilers = compilerContributors.flatMap { it.compilersFor(project, context) }.sorted()
+ val javaCompiler = allCompilers.filter { it.sourceSuffixes.contains("java") }[0]
+
+ val dependencies = dependencyManager.calculateDependencies(project, context)
+ val info = CompilerActionInfo(sourceDir.absolutePath, dependencies,
+ listOf(javaFile.absolutePath), listOf("java"), File(sourceDir, "generated"),
+ listOf())
+
+ val results = compilerUtils.invokeCompiler(project, context, javaCompiler, info)
+ }
+ }
+
private fun generated(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinAndMakeDir(project.directory, project.buildDirectory, outputDir,
context.variant.toIntermediateDir())
@@ -52,20 +108,23 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
if (!suffixesBeingCompiled.contains("java")) return emptyList()
val result = arrayListOf()
- configurationFor(project)?.let { config ->
+
+ fun addFlags(outputDir: String) {
aptDependencies[project.name]?.let { aptDependencies ->
- val deps = aptDependencies.map { dependencyManager.create(it) }
-
- val dependencies = context.dependencyManager.calculateDependencies(null, context, emptyList(), deps)
- .map { it.jarFile.get().path }
-
- result.add("-processorpath")
- result.add((dependencies).joinToString(":"))
result.add("-s")
- result.add(generated(project, context, config.outputDir))
+ result.add(generated(project, context, outputDir))
}
- log(2, "New flags from apt: " + result.joinToString(" "))
}
+
+ aptConfigs[project.name]?.let { config ->
+ addFlags(config.outputDir)
+ }
+
+ kaptConfigs[project.name]?.let { config ->
+ addFlags(config.outputDir)
+ }
+
+ log(2, "New flags from apt: " + result.joinToString(" "))
return result
}
@@ -74,15 +133,28 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
fun addAptDependency(dependencies: Dependencies, it: String) {
aptDependencies.put(dependencies.project.name, it)
}
+
+ private val aptConfigs: HashMap = hashMapOf()
+ private val kaptConfigs: HashMap = hashMapOf()
+
+ fun addAptConfig(project: Project, kapt: AptConfig) {
+ project.projectProperties.put(APT_CONFIG, kapt)
+ aptConfigs.put(project.name, kapt)
+ }
+
+ fun addKaptConfig(project: Project, kapt: KaptConfig) {
+ project.projectProperties.put(KAPT_CONFIG, kapt)
+ kaptConfigs.put(project.name, kapt)
+ }
}
class AptConfig(var outputDir: String = "generated/source/apt")
@Directive
-public fun Project.apt(init: AptConfig.() -> Unit) {
+fun Project.apt(init: AptConfig.() -> Unit) {
AptConfig().let {
it.init()
- (Kobalt.findPlugin(AptPlugin.PLUGIN_NAME) as AptPlugin).addConfiguration(this, it)
+ (Kobalt.findPlugin(AptPlugin.PLUGIN_NAME) as AptPlugin).addAptConfig(this, it)
}
}
@@ -92,3 +164,13 @@ fun Dependencies.apt(vararg dep: String) {
(Kobalt.findPlugin(AptPlugin.PLUGIN_NAME) as AptPlugin).addAptDependency(this, it)
}
}
+
+class KaptConfig(var outputDir: String = "generated/source/apt")
+
+@Directive
+fun Project.kapt(init: KaptConfig.() -> Unit) {
+ KaptConfig().let {
+ it.init()
+ (Kobalt.findPlugin(AptPlugin.PLUGIN_NAME) as AptPlugin).addKaptConfig(this, it)
+ }
+}
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt
index 0bbca05f..cad94b0f 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt
@@ -5,6 +5,7 @@ import com.beust.kobalt.api.*
import com.beust.kobalt.internal.ICompilerAction
import com.beust.kobalt.internal.JvmCompiler
import com.beust.kobalt.internal.KobaltSettings
+import com.beust.kobalt.internal.KotlinJarFiles
import com.beust.kobalt.kotlin.ParentLastClassLoader
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.dependency.FileDependency
@@ -34,7 +35,8 @@ class KotlinCompiler @Inject constructor(
val dependencyManager: DependencyManager,
val executors: KobaltExecutors,
val settings: KobaltSettings,
- val jvmCompiler: JvmCompiler) {
+ val jvmCompiler: JvmCompiler,
+ val kotlinJarFiles: KotlinJarFiles) {
val compilerAction = object: ICompilerAction {
override fun compile(projectName: String?, info: CompilerActionInfo): TaskResult {
@@ -88,29 +90,30 @@ class KotlinCompiler @Inject constructor(
log(2, "Calling kotlinc " + allArgs.joinToString(" "))
val result : TaskResult =
if (true) {
- val classLoader = ParentLastClassLoader(cp.map { it.toURI().toURL() })
- val compiler = classLoader.loadClass("org.jetbrains.kotlin.cli.common.CLICompiler")
- val compilerMain = compiler.declaredMethods.filter {
- it.name == "doMainNoExit" && it.parameterTypes.size == 2
- }[0]
- val kCompiler = classLoader.loadClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler")
-
//
// In order to capture the error stream, I need to invoke CLICompiler.exec(), which
// is the first method that accepts a PrintStream for the errors in parameter
//
- val baos = ByteArrayOutputStream()
- val ps = PrintStream(baos)
- val execMethod = compiler.declaredMethods.filter {
- it.name == "exec" && it.parameterTypes.size == 2
- }[0]
- val exitCode = execMethod.invoke(kCompiler.newInstance(), ps, allArgs.toTypedArray())
- val errorString = baos.toString(Charset.defaultCharset().toString())
+ ByteArrayOutputStream().use { baos ->
+ val compilerJar = listOf(kotlinJarFiles.compiler.toURI().toURL())
- // The return value is an enum
- val nameMethod = exitCode.javaClass.getMethod("name")
- val success = "OK" == nameMethod.invoke(exitCode).toString()
- TaskResult(success, errorString)
+ val classLoader = ParentLastClassLoader(compilerJar)
+ val compiler = classLoader.loadClass("org.jetbrains.kotlin.cli.common.CLICompiler")
+ val kCompiler = classLoader.loadClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler")
+
+ PrintStream(baos).use { ps ->
+ val execMethod = compiler.declaredMethods.filter {
+ it.name == "exec" && it.parameterTypes.size == 2
+ }[0]
+ val exitCode = execMethod.invoke(kCompiler.newInstance(), ps, allArgs.toTypedArray())
+ val errorString = baos.toString(Charset.defaultCharset().toString())
+
+ // The return value is an enum
+ val nameMethod = exitCode.javaClass.getMethod("name")
+ val success = "OK" == nameMethod.invoke(exitCode).toString()
+ TaskResult(success, errorString)
+ }
+ }
} else {
val exitCode = CLICompiler.doMainNoExit(K2JVMCompiler(), allArgs.toTypedArray())
TaskResult(exitCode == ExitCode.OK)
@@ -161,7 +164,7 @@ class KotlinCompiler @Inject constructor(
}
class KConfiguration @Inject constructor(val compiler: KotlinCompiler){
- val classpath = arrayListOf()
+ private val classpath = arrayListOf()
val dependencies = arrayListOf()
var source = arrayListOf()
var output: File by Delegates.notNull()
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt
index 4d210fa4..c0d975f3 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt
@@ -7,6 +7,7 @@ import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.BaseJvmPlugin
import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.internal.KobaltSettings
+import com.beust.kobalt.internal.KotlinJarFiles
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles
@@ -19,7 +20,8 @@ import javax.inject.Singleton
@Singleton
class KotlinPlugin @Inject constructor(val executors: KobaltExecutors, val dependencyManager: DependencyManager,
- val settings: KobaltSettings, override val configActor: ConfigActor)
+ val settings: KobaltSettings, override val configActor: ConfigActor,
+ val kotlinJarFiles: KotlinJarFiles)
: BaseJvmPlugin(configActor), IDocContributor, IClasspathContributor, ICompilerContributor, IBuildConfigContributor {
companion object {
@@ -105,8 +107,8 @@ class KotlinPlugin @Inject constructor(val executors: KobaltExecutors, val depen
override fun classpathEntriesFor(project: Project?, context: KobaltContext): List =
if (project == null || accept(project)) {
// All Kotlin projects automatically get the Kotlin runtime added to their class path
- listOf(getKotlinCompilerJar("kotlin-stdlib"), getKotlinCompilerJar("kotlin-runtime"))
- .map { FileDependency(it) }
+ listOf(kotlinJarFiles.stdlib, kotlinJarFiles.runtime)
+ .map { FileDependency(it.absolutePath) }
} else {
emptyList()
}
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt
index 16dea24c..3b1dd5b9 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/packaging/PackagingPlugin.kt
@@ -67,17 +67,20 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
* skipped.
*/
override fun assemble(project: Project, context: KobaltContext) : IncrementalTaskInfo {
- return IncrementalTaskInfo({ null }, { null }, { project ->
- try {
- packages.filter { it.project.name == project.name }.forEach { pkg ->
- pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) }
- pkg.wars.forEach { warGenerator.generateWar(pkg.project, context, it) }
- pkg.zips.forEach { zipGenerator.generateZip(pkg.project, context, it) }
- if (pkg.generatePom) {
- pomFactory.create(project).generate()
- }
- }
- TaskResult()
+ return IncrementalTaskInfo(
+ { null },
+ { null },
+ { project ->
+ try {
+ packages.filter { it.project.name == project.name }.forEach { packageConfig ->
+ packageConfig.jars.forEach { jarGenerator.generateJar(packageConfig.project, context, it) }
+ packageConfig.wars.forEach { warGenerator.generateWar(packageConfig.project, context, it) }
+ packageConfig.zips.forEach { zipGenerator.generateZip(packageConfig.project, context, it) }
+ if (packageConfig.generatePom) {
+ pomFactory.create(project).generate()
+ }
+ }
+ TaskResult()
} catch(ex: Exception) {
throw KobaltException(ex)
}}, context)
@@ -118,8 +121,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
val analyzer = Analyzer().apply {
jar = aQute.bnd.osgi.Jar(project.projectProperties.get(Archives.JAR_NAME) as String)
val dependencies = project.compileDependencies + project.compileRuntimeDependencies
- val dependentProjects = project.dependentProjects
- dependencyManager.calculateDependencies(project, context, dependentProjects, dependencies).forEach {
+ dependencyManager.calculateDependencies(project, context, dependencies).forEach {
addClasspath(it.jarFile.get())
}
setProperty(Analyzer.BUNDLE_VERSION, project.version)
@@ -152,7 +154,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
}
//ITaskContributor
- override fun tasksFor(context: KobaltContext): List = taskContributor.dynamicTasks
+ override fun tasksFor(project: Project, context: KobaltContext): List = taskContributor.dynamicTasks
}
@Directive
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/packaging/WarGenerator.kt b/src/main/kotlin/com/beust/kobalt/plugin/packaging/WarGenerator.kt
index ad4b4f8d..a4826813 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/packaging/WarGenerator.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/packaging/WarGenerator.kt
@@ -1,13 +1,12 @@
package com.beust.kobalt.plugin.packaging
-import com.beust.kobalt.archive.Archives
import com.beust.kobalt.IFileSpec
import com.beust.kobalt.JarGenerator
-import com.beust.kobalt.archive.War
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
-import com.beust.kobalt.api.ProjectDescription
+import com.beust.kobalt.archive.Archives
+import com.beust.kobalt.archive.War
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.From
import com.beust.kobalt.misc.IncludedFile
@@ -40,9 +39,7 @@ class WarGenerator @Inject constructor(val dependencyManager: DependencyManager)
// The transitive closure of libraries goes into WEB-INF/libs.
// Copy them all in kobaltBuild/war/WEB-INF/libs and create one IncludedFile out of that directory
//
- val dependentProjects = listOf(ProjectDescription(project, project.projectExtra.dependsOn))
- val allDependencies = dependencyManager.calculateDependencies(project, context, dependentProjects,
- project.compileDependencies)
+ val allDependencies = dependencyManager.calculateDependencies(project, context, project.compileDependencies)
val outDir = project.buildDirectory + "/war"
val fullDir = outDir + "/" + LIB
diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt
index d93da574..8bbd7058 100644
--- a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt
+++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt
@@ -6,26 +6,35 @@ import com.beust.kobalt.api.Project
import com.beust.kobalt.maven.Gpg
import com.beust.kobalt.maven.Http
import com.beust.kobalt.maven.Md5
+import com.beust.kobalt.misc.CountingFileRequestBody
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.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
-import com.google.gson.JsonParser
+import com.google.gson.TypeAdapter
+import com.google.gson.reflect.TypeToken
import com.google.inject.assistedinject.Assisted
-import okhttp3.*
+import okhttp3.Credentials
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
import retrofit2.Call
+import retrofit2.Converter
import retrofit2.Retrofit
-import retrofit2.converter.gson.GsonConverterFactory
-import retrofit2.http.*
-import retrofit2.http.Headers
+import retrofit2.http.Body
+import retrofit2.http.GET
+import retrofit2.http.POST
+import retrofit2.http.PUT
+import retrofit2.http.Path
import java.io.File
+import java.lang.reflect.Type
import javax.annotation.Nullable
import javax.inject.Inject
-class BintrayResponse()
-
class BintrayApi @Inject constructor(val http: Http,
@Nullable @Assisted("username") val username: String?,
@Nullable @Assisted("password") val password: String?,
@@ -34,7 +43,6 @@ class BintrayApi @Inject constructor(val http: Http,
companion object {
const val BINTRAY_URL_API = "https://api.bintray.com"
- const val BINTRAY_URL_API_CONTENT = BINTRAY_URL_API + "/content"
}
interface IFactory {
@@ -52,28 +60,15 @@ class BintrayApi @Inject constructor(val http: Http,
fun createPackage(@Path("owner") owner: String,
@Body content: JsonObject): Call
- @Multipart
- @Headers("Content-Type: application/xml")
- @PUT("/content/{owner}/maven/{repo}/{version}/{group}/{artifact}/{version}/{name}")
- fun uploadPom(@Path("owner") owner: String,
- @Path("repo") repo: String,
- @Path("group", encoded = true) group: String,
- @Path("artifact") artifact: String,
- @Path("version") version: String,
- @Path("name") name: String,
- @Part file: MultipartBody.Part): Call
-
- @Multipart
- @PUT("/content/{owner}/maven/{repo}/{version}/{group}/{artifact}/{version}/{name}")
+ @PUT("/content/{owner}/maven/{repo}/{version}/{group}/{artifact}/{version}/{name};publish={publish}")
fun uploadArtifact(@Path("owner") owner: String,
@Path("repo") repo: String,
@Path("group", encoded = true) group: String,
@Path("artifact") artifact: String,
@Path("version") version: String,
@Path("name") name: String,
- @Part file: MultipartBody.Part): Call
-
-
+ @Path("publish") publish: Int,
+ @Body file: File): Call
}
private val service: Api
@@ -84,7 +79,7 @@ class BintrayApi @Inject constructor(val http: Http,
// level = HttpLoggingInterceptor.Level.BASIC
// })
builder.interceptors().add(Interceptor { chain ->
- var original = chain.request();
+ val original = chain.request();
chain.proceed(original.newBuilder()
.header("Authorization", Credentials.basic(username, password))
@@ -96,7 +91,7 @@ class BintrayApi @Inject constructor(val http: Http,
service = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BintrayApi.BINTRAY_URL_API)
- .addConverterFactory(GsonConverterFactory.create())
+ .addConverterFactory(ConverterFactory())
.build()
.create(Api::class.java)
}
@@ -128,18 +123,18 @@ class BintrayApi @Inject constructor(val http: Http,
return jsonObject
}
- fun uploadMaven(project: Project, files: List, config: BintrayConfig?): TaskResult {
+ fun uploadMaven(project: Project, files: List, config: BintrayConfig): TaskResult {
validatePackage(project)
return upload(project, files, config, generateMd5 = true)
}
- fun uploadFile(project: Project, file: File, config: BintrayConfig?, generateMd5: Boolean = false) =
+ fun uploadFile(project: Project, file: File, config: BintrayConfig, generateMd5: Boolean = false) =
upload(project, arrayListOf(file), config, generateMd5)
- private fun upload(project: Project, files: List, config: BintrayConfig?, generateMd5: Boolean = false): TaskResult {
+ private fun upload(project: Project, files: List, config: BintrayConfig, generateMd5: Boolean): TaskResult {
val filesToUpload = arrayListOf()
- if (config != null && config.sign) {
+ if (config.sign) {
// Create the .asc files
filesToUpload.addAll(gpg.runGpg(files))
}
@@ -156,17 +151,6 @@ class BintrayApi @Inject constructor(val http: Http,
}
}
- //
- // If any configuration was given, apply them so the URL reflects them, e.g. ?publish=1
- //
- val options = arrayListOf()
- if (config?.publish == true) options.add("publish=1")
-
- val optionPath = StringBuffer()
- if (options.size > 0) {
- optionPath.append("?" + options.joinToString("&"))
- }
-
val fileCount = filesToUpload.size
if (fileCount > 0) {
log(1, " Found $fileCount artifacts to upload")
@@ -180,33 +164,21 @@ class BintrayApi @Inject constructor(val http: Http,
val results = arrayListOf()
filesToUpload.forEachIndexed { i, file ->
- val type = MediaType.parse("multipart/form-data")
+ val owner = org ?: username!!
+ val repo = project.name
+ val group = project.group!!.replace('.', '/')
+ val artifact = project.artifactId!!
+ val version = project.version!!
- val body = MultipartBody.Part.createFormData("artifact", file.name, RequestBody.create(type, file));
-
- if (file.extension != "pom") {
- val upload = service.uploadArtifact(org ?: username!!, project.name,
- project.group!!.replace('.', '/'), project.artifactId!!, project.version!!, file.name, body)
- val result = upload.execute()
- val error = result.errorBody()?.string()
- if (result.errorBody() != null) {
- errorMessages.add(error!!)
- results.add(false)
- } else {
- results.add(true)
- }
+ val result = service.uploadArtifact(owner, repo, group, artifact, version, file.name,
+ if (config.publish) 1 else 0, file)
+ .execute()
+ val error = result.errorBody()?.string()
+ if (result.errorBody() != null) {
+ errorMessages.add(error!!)
+ results.add(false)
} else {
- http.uploadFile(username, password, fileToPath(project, file) + optionPath,
- Http.TypedFile(com.google.common.net.MediaType.ANY_APPLICATION_TYPE.toString(), file),
- post = false, // Bintray requires PUT
- success = { r: Response -> results.add(true) },
- error = { r: Response ->
- results.add(false)
- val jcResponse = parseResponse(r)
- errorMessages.add(jcResponse.errorMessage!!)
- })
-// service.uploadPom(org ?: username!!, project.name, project.group!!.replace('.', '/'),
-// project.artifactId!!, project.version!!, file.name, body)
+ results.add(true)
}
log(1, " Uploading ${i + 1} / $fileCount " + dots(fileCount, results, file), false)
@@ -228,37 +200,8 @@ class BintrayApi @Inject constructor(val http: Http,
}
}
- fun fileToPath(project: Project, f: File) : String {
- return listOf(
- BINTRAY_URL_API_CONTENT,
- org ?: username!!,
- "maven",
- project.name,
- project.version!!,
- project.group!!.replace(".", "/"),
- project.artifactId!!,
- project.version!!,
- f.name)
- .joinToString("/")
- }
-
class BintrayResponse(val jo: JsonObject?, val errorMessage: String?)
- fun parseResponse(r: Response): BintrayResponse {
- val networkResponse = r.networkResponse()
- if (networkResponse.code() != 200) {
- val message = networkResponse.message()
- try {
- val errorObject = JsonParser().parse(r.body().string()).asJsonObject
- return BintrayResponse(null, message + ": " + errorObject.get("message").asString)
- } catch(ex: Exception) {
- return BintrayResponse(null, message)
- }
- } else {
- return BintrayResponse(JsonParser().parse(r.body().string()).asJsonObject, null)
- }
- }
-
fun JsonObject.addNonNull(name: String, value: String?) {
if (value != null) {
addProperty(name, value);
@@ -266,3 +209,31 @@ class BintrayApi @Inject constructor(val http: Http,
}
}
+
+class ConverterFactory : Converter.Factory() {
+ override fun responseBodyConverter(type: Type, annotations: Array, retrofit: Retrofit): Converter? {
+ return GsonResponseBodyConverter(Gson(), Gson().getAdapter(TypeToken.get(type)))
+ }
+
+ override fun requestBodyConverter(type: Type, parameterAnnotations: Array, methodAnnotations: Array,
+ retrofit: Retrofit?): Converter<*, RequestBody>? {
+ return RequestBodyConverter()
+ }
+}
+
+class GsonResponseBodyConverter(private val gson: Gson, private val adapter: TypeAdapter) : Converter