1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 00:17:11 -07:00

Merge branch 'master' of github.com:cbeust/kobalt

This commit is contained in:
Cedric Beust 2017-04-21 12:17:34 -07:00
commit 49e69d0964
22 changed files with 445 additions and 168 deletions

10
dist/kobaltw vendored
View file

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

View file

@ -43,7 +43,6 @@ object Versions {
val junitVintageVersion = "$junit.0-M4"
}
fun mavenResolver(vararg m: String)
= m.map { "org.apache.maven.resolver:maven-resolver-$it:${Versions.mavenResolver}" }
.toTypedArray()
@ -114,7 +113,7 @@ val kobaltPluginApi = project {
"org.slf4j:slf4j-simple:${Versions.slf4j}",
*mavenResolver("api", "spi", "util", "impl", "connector-basic", "transport-http", "transport-file"),
"org.apache.maven:maven-aether-provider:3.3.9",
"org.testng.testng-remote:testng-remote:1.3.0",
"org.testng.testng-remote:testng-remote:1.3.2",
"org.testng:testng:${Versions.testng}",
"commons-io:commons-io:2.5",
"org.junit.platform:junit-platform-surefire-provider:${Versions.junitPlatform}",
@ -140,12 +139,8 @@ val kobaltPluginApi = project {
}
}
// install {
// libDir = "lib-test"
// }
kotlinCompiler {
args("-nowarn")
args("nowarn")
}
bintray {
@ -233,7 +228,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
}
kotlinCompiler {
args("-nowarn")
args("nowarn")
}
bintray {

View file

@ -1 +1 @@
kobalt.version=1.0.62
kobalt.version=1.0.72

View file

@ -74,8 +74,18 @@ data class ProxyConfig(val host: String = "", val port: Int = 0, val type: Strin
fun toAetherProxy() = Proxy(type, host, port) // TODO make support for proxy auth
}
data class HostConfig(var url: String = "", var name: String = url, var username: String? = null,
var password: String? = null) {
data class HostConfig(var url: String = "", var name: String = HostConfig.createRepoName(url),
var username: String? = null, var password: String? = null) {
companion object {
/**
* For repos specified in the build file (repos()) that don't have an associated unique name,
* create such a name from the URL. This is a requirement from Maven Resolver, and failing to do
* this leads to very weird resolution errors.
*/
private fun createRepoName(url: String) = url.replace("/", "_").replace("\\", "_").replace(":", "_")
}
fun hasAuth() : Boolean {
return (! username.isNullOrBlank()) && (! password.isNullOrBlank())
}
@ -106,6 +116,7 @@ fun buildFileClasspath(vararg deps: String) {
}
fun newBuildFileClasspath(vararg deps: String) {
//FIXME newBuildFileClasspath called twice
deps.forEach { Kobalt.addBuildFileClasspath(it) }
}
@ -115,7 +126,7 @@ fun authRepos(vararg repos : HostConfig) {
}
@Directive
fun authRepo(init: HostConfig.() -> Unit) = HostConfig().apply { init() }
fun authRepo(init: HostConfig.() -> Unit) = HostConfig(name = "").apply { init() }
@Directive
fun glob(g: String) : IFileSpec.GlobSpec = IFileSpec.GlobSpec(g)

View file

@ -2,8 +2,10 @@ package com.beust.kobalt
class SystemProperties {
companion object {
val javaBase = System.getProperty("java.home") ?:
(System.getenv("JAVA_HOME") ?: throw IllegalArgumentException("JAVA_HOME not defined"))
val javaBase =
System.getenv("JAVA_HOME")
?: System.getProperty("java.home")
?: throw IllegalArgumentException("JAVA_HOME not defined")
val javaVersion = System.getProperty("java.version")
val homeDir = System.getProperty("user.home")
val tmpDir = System.getProperty("java.io.tmpdir")

View file

@ -12,4 +12,5 @@ data class CompilerActionInfo(val directory: String?,
val outputDir: File,
val compilerArgs: List<String>,
val friendPaths: List<String>,
val forceRecompile: Boolean)
val forceRecompile: Boolean,
val compilerSeparateProcess: Boolean = false)

View file

@ -5,6 +5,7 @@ import com.beust.kobalt.HostConfig
import com.beust.kobalt.Plugins
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.google.inject.Guice
import com.google.inject.Injector
import com.google.inject.Module
@ -55,6 +56,9 @@ class Kobalt {
// Repos from the build file
result.addAll(reposFromBuildFiles)
result.forEach {
KobaltMavenResolver.initAuthentication(it)
}
return result.toHashSet()
}
@ -131,6 +135,7 @@ class Kobalt {
fun cleanUp() {
buildSourceDirs.clear()
buildFileClasspath.clear()
}
}
}

View file

@ -4,6 +4,7 @@ import com.beust.kobalt.*
import com.beust.kobalt.api.*
import com.beust.kobalt.misc.KFiles
import com.google.common.annotations.VisibleForTesting
import com.google.inject.Inject
import java.io.File
import java.util.*
@ -19,6 +20,9 @@ abstract class GenericTestRunner: ITestRunnerContributor {
open var shortMessage: String? = null
open var longMessage: String? = null
@Inject
private lateinit var jvm: Jvm
abstract fun args(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
testConfig: TestConfig) : List<String>
@ -26,7 +30,7 @@ abstract class GenericTestRunner: ITestRunnerContributor {
open val extraClasspath: List<String> = emptyList()
open fun filterTestClasses(classes: List<String>) : List<String> = classes
open fun filterTestClasses(project: Project, context: KobaltContext, classes: List<String>) : List<String> = classes
override fun run(project: Project, context: KobaltContext, configName: String,
classpath: List<IClasspathDependency>) : TaskResult {
@ -65,7 +69,7 @@ abstract class GenericTestRunner: ITestRunnerContributor {
// }
context.logger.log(project.name, 2, "Found ${result.size} test classes")
return filterTestClasses(result.map { it.second })
return filterTestClasses(project, context, result.map { it.second })
}
/**
@ -116,7 +120,7 @@ abstract class GenericTestRunner: ITestRunnerContributor {
val args = args(project, context, classpath, testConfig)
if (args.size > 0) {
val java = JavaInfo.create(File(SystemProperties.javaBase)).javaExecutable
val java = jvm.javaExecutable
val jvmArgs = calculateAllJvmArgs(project, context, testConfig, classpath,
Kobalt.INJECTOR.getInstance (PluginInfo::class.java))
val allArgs = arrayListOf<String>().apply {

View file

@ -4,6 +4,10 @@ import com.beust.kobalt.TestConfig
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.maven.DependencyManager
import com.google.inject.Inject
import java.lang.reflect.Modifier
import java.net.URLClassLoader
open class JUnitRunner() : GenericTestRunner() {
@ -14,5 +18,15 @@ open class JUnitRunner() : GenericTestRunner() {
override fun args(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>,
testConfig: TestConfig) = findTestClasses(project, context, testConfig)
@Inject
lateinit var dependencyManager: DependencyManager
override fun filterTestClasses(project: Project, context: KobaltContext, classes: List<String>) : List<String> {
val deps = dependencyManager.testDependencies(project, context)
val cl = URLClassLoader(deps.map { it.jarFile.get().toURI().toURL() }.toTypedArray())
return classes.filter { !Modifier.isAbstract(cl.loadClass(it).modifiers) }
}
}

View file

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

View file

@ -1,9 +1,8 @@
package com.beust.kobalt.maven
import com.beust.kobalt.HostConfig
import com.beust.kobalt.KobaltException
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.LocalProperties
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
@ -21,27 +20,7 @@ class Kurl(val hostInfo: HostConfig) {
}
init {
// See if the URL needs to be authenticated. Look in local.properties for keys
// of the format authUrl.<host>.user=xxx and authUrl.<host>.password=xxx
val properties = LocalProperties().localProperties
val host = java.net.URL(hostInfo.url).host
properties.entries.forEach {
val key = it.key.toString()
if (key == "$KEY.$host.$VALUE_USER") {
hostInfo.username = properties.getProperty(key)
} else if (key == "$KEY.$host.$VALUE_PASSWORD") {
hostInfo.password = properties.getProperty(key)
}
}
fun error(s1: String, s2: String) {
throw KobaltException("Found \"$s1\" but not \"$s2\" in local.properties for $KEY.$host",
docUrl = "http://beust.com/kobalt/documentation/index.html#maven-repos-authenticated")
}
if (! hostInfo.username.isNullOrBlank() && hostInfo.password.isNullOrBlank()) {
error("username", "password")
} else if(hostInfo.username.isNullOrBlank() && ! hostInfo.password.isNullOrBlank()) {
error("password", "username")
}
KobaltMavenResolver.initAuthentication(hostInfo)
}
override fun toString() = hostInfo.toString()

View file

@ -2,11 +2,14 @@ package com.beust.kobalt.maven.aether
import com.beust.kobalt.Args
import com.beust.kobalt.HostConfig
import com.beust.kobalt.KobaltException
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.getProxy
import com.beust.kobalt.maven.Kurl
import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.MavenId
import com.beust.kobalt.misc.LocalProperties
import com.google.common.eventbus.EventBus
import com.google.inject.Inject
import org.eclipse.aether.artifact.Artifact
@ -21,6 +24,7 @@ import org.eclipse.aether.resolution.DependencyRequest
import org.eclipse.aether.resolution.DependencyResult
import org.eclipse.aether.resolution.VersionRangeRequest
import org.eclipse.aether.resolution.VersionRangeResult
import org.eclipse.aether.util.repository.AuthenticationBuilder
import java.util.*
class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings,
@ -32,6 +36,31 @@ class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings,
MavenId.toId(it.groupId, it.artifactId, it.extension, it.classifier, it.version)
}
fun isRangeVersion(id: String) = id.contains(",")
fun initAuthentication(hostInfo: HostConfig) {
// See if the URL needs to be authenticated. Look in local.properties for keys
// of the format authUrl.<host>.user=xxx and authUrl.<host>.password=xxx
val properties = LocalProperties().localProperties
val host = java.net.URL(hostInfo.url).host
properties.entries.forEach {
val key = it.key.toString()
if (key == "${Kurl.KEY}.$host.${Kurl.VALUE_USER}") {
hostInfo.username = properties.getProperty(key)
} else if (key == "${Kurl.KEY}.$host.${Kurl.VALUE_PASSWORD}") {
hostInfo.password = properties.getProperty(key)
}
}
fun error(s1: String, s2: String) {
throw KobaltException("Found \"$s1\" but not \"$s2\" in local.properties for ${Kurl.KEY}.$host",
docUrl = "http://beust.com/kobalt/documentation/index.html#maven-repos-authenticated")
}
if (! hostInfo.username.isNullOrBlank() && hostInfo.password.isNullOrBlank()) {
error("username", "password")
} else if(hostInfo.username.isNullOrBlank() && ! hostInfo.password.isNullOrBlank()) {
error("password", "username")
}
}
}
fun resolveToArtifact(id: String, scope: Scope? = null,
@ -110,8 +139,17 @@ class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings,
private val system = Booter.newRepositorySystem()
private val session = Booter.newRepositorySystemSession(system, localRepo.localRepo, settings, eventBus)
private fun createRepo(hostConfig: HostConfig) =
RemoteRepository.Builder(hostConfig.name, "default", hostConfig.url).build()
private fun createRepo(hostConfig: HostConfig) : RemoteRepository {
val builder = RemoteRepository.Builder(hostConfig.name, "default", hostConfig.url)
if (hostConfig.hasAuth()) {
val auth = AuthenticationBuilder()
.addUsername(hostConfig.username)
.addPassword(hostConfig.password)
.build()
builder.setAuthentication(auth)
}
return builder.build()
}
private val kobaltRepositories: List<RemoteRepository>
get() = Kobalt.repos.map {

View file

@ -79,9 +79,11 @@ open class NewRunCommand(val info: RunCommandInfo) {
// Run the command and collect the return code and streams
val returnCode = process.waitFor(30, TimeUnit.SECONDS)
val input = if (process.inputStream.available() > 0) fromStream(process.inputStream)
val input =
if (process.inputStream.available() > 0) fromStream(process.inputStream)
else listOf()
val error = if (process.errorStream.available() > 0) fromStream(process.errorStream)
val error =
if (process.errorStream.available() > 0) fromStream(process.errorStream)
else listOf()
// Check to see if the command succeeded
@ -105,10 +107,10 @@ open class NewRunCommand(val info: RunCommandInfo) {
open protected fun isSuccess(isSuccess: Boolean, input: List<String>, error: List<String>) : Boolean {
var hasErrors = ! isSuccess
if (info.useErrorStreamAsErrorIndicator && ! hasErrors) {
hasErrors = hasErrors || error.size > 0
hasErrors = hasErrors || error.isNotEmpty()
}
if (info.useInputStreamAsErrorIndicator && ! hasErrors) {
hasErrors = hasErrors || input.size > 0
hasErrors = hasErrors || input.isNotEmpty()
}
return ! hasErrors

View file

@ -3,6 +3,7 @@ package com.beust.kobalt
import com.beust.jcommander.JCommander
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginTask
import com.beust.kobalt.api.Project
import com.beust.kobalt.app.ProjectFinder
import com.beust.kobalt.app.ProjectGenerator
import com.beust.kobalt.app.Templates
@ -44,10 +45,26 @@ class Options @Inject constructor(
val p = if (args.buildFile != null) File(args.buildFile) else File(".")
// val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
val buildSources = if (p.isDirectory) BuildSources(p.absoluteFile) else SingleFileBuildSources(p)
var pluginClassLoader = javaClass.classLoader
val pluginClassLoader = javaClass.classLoader
val allProjectResult = projectFinder.initForBuildFile(buildSources, args)
val allProjects = allProjectResult.projects
//
// Attempt to parse the build file in order to correctly set up repos, plug-ins, etc...
// If the build file can't be parsed, don't give up just yet since some options don't need
// a correct build file to work.
//
var buildError: Throwable? = null
val allProjects =
try {
projectFinder.initForBuildFile(buildSources, args).projects
} catch(ex: Exception) {
buildError = ex
listOf<Project>()
}
fun runIfSuccessfulBuild(buildError: Throwable?, action: () -> Unit) {
buildError?.let { throw it }
action()
}
// Modify `args` with options found in buildScript { kobaltOptions(...) }, if any
addOptionsFromBuild(args, Kobalt.optionsFromBuild)
@ -77,11 +94,13 @@ class Options @Inject constructor(
}),
Option( { -> args.projectInfo }, {
// --projectInfo
runIfSuccessfulBuild(buildError) {
allProjects.forEach {
it.compileDependencies.filter { it.isMaven }.forEach {
resolveDependency.run(it.id)
}
}
}
}),
Option( { args.dependency != null }, {
// --resolve
@ -89,11 +108,15 @@ class Options @Inject constructor(
}),
Option( { args.tasks }, {
// --tasks
runIfSuccessfulBuild(buildError) {
displayTasks()
}
}),
Option( { args.checkVersions }, {
// --checkVersions
runIfSuccessfulBuild(buildError) {
checkVersions.run(allProjects)
}
}),
Option( { args.download }, {
// --download
@ -121,6 +144,7 @@ class Options @Inject constructor(
if (! buildSources.exists()) {
throw KobaltException("Could not find build file: " + buildSources)
}
runIfSuccessfulBuild(buildError) {
val runTargetResult = taskManager.runTargets(args.targets, allProjects)
if (result == 0) {
result = if (runTargetResult.taskResult.success) 0 else 1
@ -134,6 +158,7 @@ class Options @Inject constructor(
it.generateReport(Kobalt.context!!)
}
}
}
return result
}

View file

@ -1,6 +1,8 @@
package com.beust.kobalt.app
import com.beust.kobalt.Args
import com.beust.kobalt.JavaInfo
import com.beust.kobalt.Jvm
import com.beust.kobalt.app.remote.KobaltServer
import com.beust.kobalt.internal.IncrementalManager
import com.beust.kobalt.internal.KobaltSettings
@ -17,6 +19,7 @@ import com.google.inject.Provider
import com.google.inject.Singleton
import com.google.inject.TypeLiteral
import com.google.inject.assistedinject.FactoryModuleBuilder
import java.io.File
import java.util.concurrent.ExecutorService
open class MainModule(val args: Args, val settings: KobaltSettings) : AbstractModule() {
@ -49,15 +52,14 @@ open class MainModule(val args: Args, val settings: KobaltSettings) : AbstractMo
bind(Args::class.java).toProvider(Provider<Args> {
args
})
EventBus().let { eventBus ->
bind(EventBus::class.java).toInstance(eventBus)
}
bind(EventBus::class.java).toInstance(EventBus())
bind(PluginInfo::class.java).toProvider(Provider<PluginInfo> {
PluginInfo.readKobaltPluginXml()
}).`in`(Singleton::class.java)
bind(KobaltSettings::class.java).toProvider(Provider<KobaltSettings> {
settings
}).`in`(Singleton::class.java)
bind(Jvm::class.java).toInstance(JavaInfo.create(File(com.beust.kobalt.SystemProperties.javaBase)))
// bindListener(Matchers.any(), object: TypeListener {
// override fun <I> hear(typeLiteral: TypeLiteral<I>?, typeEncounter: TypeEncounter<I>?) {

View file

@ -2,6 +2,7 @@ package com.beust.kobalt.app.remote
import com.beust.kobalt.Args
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project
import com.beust.kobalt.app.BuildFileCompiler
import com.beust.kobalt.internal.DynamicGraph
@ -29,7 +30,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
val taskManager: TaskManager) {
fun dependenciesDataFor(buildSources: BuildSources, args: Args,
findProjectResult: BuildFileCompiler.FindProjectResult,
projectResult: BuildFileCompiler.FindProjectResult,
progressListener: IProgressListener? = null,
useGraph : Boolean = false): GetDependenciesData {
val projectDatas = arrayListOf<ProjectData>()
@ -42,9 +43,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
fun allDeps(l: List<IClasspathDependency>, name: String) = dependencyManager.transitiveClosure(l,
requiredBy = name)
// val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
val buildFileCompiler = buildFileCompilerFactory.create(buildSources, pluginInfo)
val projectResult = buildFileCompiler.compileBuildFiles(args)
val buildFileDependencies = Kobalt.buildFileClasspath.map {toDependencyData(it, "compile")}
val pluginDependencies = projectResult.pluginUrls.map { File(it.toURI()) }.map {
DependencyData(it.name, "compile", it.absolutePath)
@ -176,8 +175,8 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
})
}
return GetDependenciesData(projectDatas, allTasks, pluginDependencies, findProjectResult.buildContentRoots,
projectResult.taskResult.errorMessage)
return GetDependenciesData(projectDatas, allTasks, pluginDependencies, buildFileDependencies,
projectResult.buildContentRoots, projectResult.taskResult.errorMessage)
}
/////
@ -202,6 +201,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
class GetDependenciesData(val projects: List<ProjectData> = emptyList(),
val allTasks: Collection<TaskData> = emptySet(),
val pluginDependencies: List<DependencyData> = emptyList(),
val buildFileDependencies: List<DependencyData> = emptyList(),
val buildContentRoots: List<String> = emptyList(),
val errorMessage: String?) {
companion object {

View file

@ -1,6 +1,9 @@
package com.beust.kobalt.plugin.application
import com.beust.kobalt.*
import com.beust.kobalt.Jvm
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.api.annotation.Task
@ -42,7 +45,7 @@ fun Project.application(init: ApplicationConfig.() -> Unit): ApplicationConfig {
@Singleton
class ApplicationPlugin @Inject constructor(val configActor: ConfigActor<ApplicationConfig>,
val executors: KobaltExecutors, val nativeManager: NativeManager,
val dependencyManager: DependencyManager, val taskContributor : TaskContributor)
val dependencyManager: DependencyManager, val taskContributor : TaskContributor, val jvm: Jvm)
: BasePlugin(), IRunnerContributor, ITaskContributor, IConfigActor<ApplicationConfig> by configActor {
companion object {
@ -111,7 +114,7 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor<Applica
@Suppress("UNCHECKED_CAST")
val packages = project.projectProperties.get(PackagingPlugin.PACKAGES) as List<PackageConfig>
val allDeps = arrayListOf(jarName)
val java = JavaInfo.create(File(SystemProperties.javaBase)).javaExecutable!!
val java = jvm.javaExecutable!!
if (! isFatJar(packages, jarName)) {
@Suppress("UNCHECKED_CAST")
// If the jar file is not fat, we need to add the transitive closure of all dependencies

View file

@ -1,10 +1,20 @@
package com.beust.kobalt.plugin.apt
import com.beust.kobalt.Constants
import com.beust.kobalt.Jvm
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.AnnotationDefault
import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.CompilerUtils
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltLogger
import com.beust.kobalt.misc.warn
import com.beust.kobalt.plugin.kotlin.KotlinPlugin
import com.google.common.collect.ArrayListMultimap
import com.google.inject.Inject
import java.io.File
@ -12,21 +22,62 @@ import java.util.*
import javax.inject.Singleton
/**
* The AptPlugin has two components:
* The AptPlugin manages both apt and kapt. Each of them has two components:
* 1) A new apt directive inside a dependency{} block (similar to compile()) that declares where
* the annotation processor is found
* 2) An apt{} configuration on Project that lets the user configure how the annotation is performed
* (outputDir, etc...).
*/
@Singleton
class AptPlugin @Inject constructor(val dependencyManager: DependencyManager)
: BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor {
class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, val kotlinPlugin: KotlinPlugin,
val compilerUtils: CompilerUtils, val jvm: Jvm)
: BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor, IClasspathContributor, ITaskContributor {
// ISourceDirectoryContributor
companion object {
const val PLUGIN_NAME = "Apt"
const val KAPT_CONFIG = "kaptConfig"
const val APT_CONFIG = "aptConfig"
}
override val name = PLUGIN_NAME
var kaptConfig: KaptConfig? = null
override fun apply(project: Project, context: KobaltContext) {
super.apply(project, context)
kaptConfig = kaptConfigs[project.name]
// Delete the output directories
listOf(aptConfigs[project.name]?.outputDir, kaptConfig?.outputDir)
.filterNotNull()
.distinct()
.map { generatedDir(project, it) }
.forEach {
it.normalize().absolutePath.let { path ->
context.logger.log(project.name, 1, " Deleting " + path)
val success = it.deleteRecursively()
if (!success) warn(" Couldn't delete " + path)
}
}
}
// IClasspathContributor
override fun classpathEntriesFor(project: Project?, context: KobaltContext): Collection<IClasspathDependency> {
val result = arrayListOf<IClasspathDependency>()
if (project != null && kaptConfig != null) {
kaptConfig?.let { config ->
val c = generatedClasses(project, context, config.outputDir)
File(c).mkdirs()
result.add(FileDependency(c))
}
}
return result
}
private fun generatedDir(project: Project, outputDir: String) : File
= File(KFiles.joinDir(project.directory, KFiles.KOBALT_BUILD_DIR, outputDir))
// ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List<File> {
val result = arrayListOf<File>()
aptConfigs[project.name]?.let { config ->
@ -40,43 +91,157 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager)
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) {
listOf(aptConfigs[project.name]?.outputDir, aptConfigs[project.name]?.outputDir)
.filterNotNull()
.distinct()
.map { generatedDir(project, it) }
.forEach {
it.normalize().absolutePath.let { path ->
context.logger.log(project.name, 1, " Deleting " + path)
val success = it.deleteRecursively()
if (!success) warn(" Couldn't delete " + path)
}
}
}
private fun generated(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinAndMakeDir(project.directory, project.buildDirectory, outputDir,
context.variant.toIntermediateDir())
KFiles.joinAndMakeDir(project.directory, project.buildDirectory, outputDir)
private fun generatedSources(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinDir(generated(project, context, outputDir), "sources")
private fun generatedStubs(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinDir(generated(project, context, outputDir), "stubs")
private fun generatedClasses(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinDir(generated(project, context, outputDir), "classes")
// ITaskContributor
override fun tasksFor(project: Project, context: KobaltContext): List<DynamicTask> {
val result =
if (kaptConfig != null) {
listOf(
DynamicTask(this, "runKapt", "Run kapt", AnnotationDefault.GROUP, project,
reverseDependsOn = listOf("compile"), runAfter = listOf("clean"),
closure = {p: Project -> taskRunKapt(p)}),
DynamicTask(this, "compileKapt", "Compile the sources generated by kapt",
AnnotationDefault.GROUP, project,
dependsOn = listOf("runKapt"), reverseDependsOn = listOf("compile"),
closure = {p: Project -> taskCompileKapt(p)})
)
} else {
emptyList()
}
return result
}
fun taskCompileKapt(project: Project) : TaskResult {
var success = true
kaptConfigs[project.name]?.let { config ->
val sourceDirs = listOf(
generatedStubs(project, context, config.outputDir),
generatedSources(project, context, config.outputDir))
val sourceFiles = KFiles.findSourceFiles(project.directory, sourceDirs, listOf("kt")).toList()
val buildDirectory = File(KFiles.joinDir(project.directory,
generatedClasses(project, context, config.outputDir)))
val flags = listOf<String>()
val cai = CompilerActionInfo(project.directory, allDependencies(project), sourceFiles, listOf(".kt"),
buildDirectory, flags, emptyList(), forceRecompile = true, compilerSeparateProcess = true)
val cr = compilerUtils.invokeCompiler(project, context, kotlinPlugin.compiler, cai)
success = cr.failedResult == null
}
return TaskResult(success)
}
val annotationDependencyId = "org.jetbrains.kotlin:kotlin-annotation-processing:" +
Constants.KOTLIN_COMPILER_VERSION
fun annotationProcessorDependency() = dependencyManager.create(annotationDependencyId)
fun aptJarDependencies(project: Project) = aptDependencies[project.name].map { dependencyManager.create(it) }
fun allDependencies(project: Project): List<IClasspathDependency> {
val allDeps = arrayListOf<IClasspathDependency>()
allDeps.add(annotationProcessorDependency())
allDeps.addAll(aptJarDependencies(project))
return allDeps
}
fun taskRunKapt(project: Project) : TaskResult {
var success = true
val flags = arrayListOf<String>()
kaptConfig?.let { config ->
val generated = generated(project, context, config.outputDir)
val generatedSources = generatedSources(project, context, config.outputDir).replace("//", "/")
File(generatedSources).mkdirs()
//
// Tell the Kotlin compiler to use the annotation plug-in
//
val allDeps = allDependencies(project)
flags.add("-Xplugin")
flags.add(annotationProcessorDependency().jarFile.get().absolutePath)
// Also need tools.jar on the plug-in classpath
jvm.toolsJar?.let { toolsJar ->
flags.add("-Xplugin")
flags.add(toolsJar.absolutePath)
}
aptJarDependencies(project).forEach {
flags.add("-Xplugin")
flags.add(it.jarFile.get().absolutePath)
}
//
// Pass options to the annotation plugin
//
flags.add("-P")
fun kaptPluginFlag(flagValue: String) = "plugin:org.jetbrains.kotlin.kapt3:$flagValue"
val kaptPluginFlags = arrayListOf<String>()
val verbose = KobaltLogger.LOG_LEVEL >= 2
listOf("sources=" + generatedSources,
"classes=" + generatedClasses(project, context, config.outputDir),
"stubs=" + generatedStubs(project, context, config.outputDir),
"verbose=$verbose",
"aptOnly=true").forEach {
kaptPluginFlags.add(kaptPluginFlag(it))
}
//
// Dependencies for the annotation plug-in and the generation
//
val dependencies = dependencyManager.calculateDependencies(project, context,
Filters.EXCLUDE_OPTIONAL_FILTER,
listOf(Scope.COMPILE),
allDeps)
dependencies.forEach {
val jarFile = it.jarFile.get().absolutePath
kaptPluginFlags.add(kaptPluginFlag("apclasspath=$jarFile"))
}
flags.add(kaptPluginFlags.joinToString(","))
listOf("-language-version", "1.1", "-api-version", "1.1").forEach {
flags.add(it)
}
val sourceFiles =
KFiles.findSourceFiles(project.directory, project.sourceDirectories, listOf("kt"))
.toList() + generatedSources
val buildDirectory = File(KFiles.joinDir(project.directory, generated))
val cai = CompilerActionInfo(project.directory, allDeps, sourceFiles, listOf(".kt"),
buildDirectory, flags, emptyList(), forceRecompile = true, compilerSeparateProcess = true)
context.logger.log(project.name, 2, " " + kaptPluginFlags.joinToString("\n "))
val cr = compilerUtils.invokeCompiler(project, context, kotlinPlugin.compiler, cai)
success = cr.failedResult == null
}
return TaskResult(success)
}
// ICompilerFlagContributor
override fun compilerFlagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>): List<String> {
if (!suffixesBeingCompiled.contains("java")) return emptyList()
val result = arrayListOf<String>()
// Only run for Java files
if (!suffixesBeingCompiled.contains("java")) return emptyList()
fun addFlags(outputDir: String) {
aptDependencies[project.name]?.let {
result.add("-s")
result.add(generated(project, context, outputDir))
result.add(generatedSources(project, context, outputDir))
}
}
@ -84,10 +249,6 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager)
addFlags(config.outputDir)
}
kaptConfigs[project.name]?.let { config ->
addFlags(config.outputDir)
}
context.logger.log(project.name, 2, "New flags from apt: " + result.joinToString(" "))
return result
}

View file

@ -1,7 +1,6 @@
package com.beust.kobalt.plugin.java
import com.beust.kobalt.JavaInfo
import com.beust.kobalt.SystemProperties
import com.beust.kobalt.Jvm
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.*
import com.beust.kobalt.internal.CompilerUtils
@ -22,7 +21,7 @@ import javax.tools.ToolProvider
@Singleton
class JavaCompiler @Inject constructor(val jvmCompiler: JvmCompiler, val kobaltLog: ParallelLogger,
val compilerUtils: CompilerUtils) : ICompiler {
val compilerUtils: CompilerUtils, val jvm: Jvm) : ICompiler {
fun compilerAction(executable: File) = object : ICompilerAction {
override fun compile(project: Project?, info: CompilerActionInfo): TaskResult {
val projectName = project?.name
@ -119,7 +118,7 @@ class JavaCompiler @Inject constructor(val jvmCompiler: JvmCompiler, val kobaltL
-> it.compilerFlagsFor(project, context, currentFlags, suffixesBeingCompiled) }
FlagContributor(it.flagPriority, closure)
}
return run(project, context, info, JavaInfo.create(File(SystemProperties.javaBase)).javacExecutable!!,
return run(project, context, info, jvm.javacExecutable!!,
compilerUtils.compilerFlags(project, context, info, adapters))
}
@ -130,7 +129,7 @@ class JavaCompiler @Inject constructor(val jvmCompiler: JvmCompiler, val kobaltL
-> it.docFlagsFor(project, context, currentFlags, suffixesBeingCompiled) }
FlagContributor(it.flagPriority, closure)
}
return run(project, context, info, JavaInfo.create(File(SystemProperties.javaBase)).javadocExecutable!!,
return run(project, context, info, jvm.javadocExecutable!!,
compilerUtils.compilerFlags(project, context, info, adapters))
}
}

View file

@ -35,7 +35,8 @@ class KotlinCompiler @Inject constructor(
val settings: KobaltSettings,
val jvmCompiler: JvmCompiler,
val compilerUtils: CompilerUtils,
val kobaltLog: ParallelLogger) {
val kobaltLog: ParallelLogger,
val jvm: Jvm) {
val compilerAction = object: ICompilerAction {
override fun compile(project: Project?, info: CompilerActionInfo): TaskResult {
@ -44,6 +45,7 @@ class KotlinCompiler @Inject constructor(
var filesToCompile = 0
if (! info.outputDir.path.endsWith("ript.jar")) {
// Don't display the message if compiling Build.kt
if (info.sourceFiles.isNotEmpty()) {
filesToCompile =
info.sourceFiles.map(::File).map {
if (it.isDirectory) KFiles.findRecursively(it).size else 1
@ -53,6 +55,7 @@ class KotlinCompiler @Inject constructor(
kobaltLog.log(projectName ?: "", 1,
" Kotlin $version compiling " + Strings.pluralizeAll(filesToCompile, "file"))
}
}
val cp = compilerFirst(info.dependencies.map { it.jarFile.get() })
val infoDir = info.directory
val outputDir =
@ -86,7 +89,8 @@ class KotlinCompiler @Inject constructor(
// the K2JVMCompiler class directly
val actualVersion = kotlinVersion(project)
if (settings.kobaltCompilerSeparateProcess || actualVersion != Constants.KOTLIN_COMPILER_VERSION) {
if (settings.kobaltCompilerSeparateProcess || actualVersion != Constants.KOTLIN_COMPILER_VERSION
|| info.compilerSeparateProcess) {
return invokeCompilerInSeparateProcess(classpath, info, actualVersion, project)
} else {
@ -97,7 +101,7 @@ class KotlinCompiler @Inject constructor(
private fun invokeCompilerInSeparateProcess(classpath: String, info: CompilerActionInfo,
compilerVersion: String, project: Project?): TaskResult {
val java = JavaInfo.create(File(SystemProperties.javaBase)).javaExecutable
val java = jvm.javaExecutable
val compilerClasspath = compilerDep(compilerVersion).jarFile.get().path + File.pathSeparator +
compilerEmbeddableDependencies(null, compilerVersion).map { it.jarFile.get().path }
@ -111,20 +115,24 @@ class KotlinCompiler @Inject constructor(
val newArgs = listOf(
"-classpath", compilerClasspath,
K2JVMCompiler::class.java.name,
*info.compilerArgs.toTypedArray(),
"-classpath", classpath,
"-d", info.outputDir.absolutePath,
*xFlagsArray,
*info.sourceFiles.toTypedArray())
.filter { ! it.isEmpty() }
log(2, " Invoking separate kotlinc:\n " + java!!.absolutePath + " " + newArgs.joinToString())
log(2, " Invoking separate kotlinc:\n " + java!!.absolutePath + " " + newArgs.joinToString(" "))
val result = NewRunCommand(RunCommandInfo().apply {
command = java.absolutePath
args = newArgs
directory = File(".")
// The Kotlin compiler issues warnings on stderr :-(
containsErrors = { errors: List<String> -> errors.any { it.contains("rror")} }
// // The Kotlin compiler issues warnings on stderr :-(
useErrorStreamAsErrorIndicator = false
// containsErrors = {
// errors: List<String> -> errors.any { it.contains("rror")}
// }
}).invoke()
return TaskResult(result == 0, errorMessage = "Error while compiling")
}
@ -135,7 +143,8 @@ class KotlinCompiler @Inject constructor(
val friends = info.friendPaths.toTypedArray()
// Collect the compiler args from kotlinCompiler{} and from settings.xml and parse them
val args2 = (kotlinConfig(project)?.args ?: arrayListOf<String>()) +
val args2 =
info.compilerArgs +
(settings.kobaltCompilerFlags?.split(" ") ?: listOf<String>())
val args = K2JVMCompilerArguments()
val compiler = K2JVMCompiler()
@ -185,13 +194,27 @@ class KotlinCompiler @Inject constructor(
fun logk(level: Int, message: CharSequence) = kobaltLog.log(projectName, level, message)
logk(2, " Invoking K2JVMCompiler with arguments:"
fun pluginClasspaths(args: K2JVMCompilerArguments) : String {
var result = ""
args.pluginClasspaths?.forEach {
result += " -Xplugin " + it
}
args.pluginOptions?.let {
result += " -P "
result += it.joinToString(",")
}
return result
}
logk(2, " Invoking K2JVMCompiler with arguments: kotlinc "
+ if (args.skipMetadataVersionCheck) " -Xskip-metadata-version-check" else ""
+ " -moduleName " + args.moduleName
+ " -d " + args.destination
+ " -friendPaths " + args.friendPaths.joinToString(";")
+ " -classpath " + args.classpath
+ pluginClasspaths(args)
+ " " + sourceFiles.joinToString(" "))
logk(2, " Additional kotlinc arguments: "
+ " -moduleName " + args.moduleName
+ " -friendPaths " + args.friendPaths.joinToString(";"))
val collector = object : MessageCollector {
override fun clear() {
throw UnsupportedOperationException("not implemented")
@ -214,7 +237,6 @@ class KotlinCompiler @Inject constructor(
message: String, location: CompilerMessageLocation) {
if (severity.isError) {
"Couldn't compile file: ${dump(location, message)}".let { fullMessage ->
System.err.println(fullMessage)
throw KobaltException(fullMessage)
}
} else if (severity == CompilerMessageSeverity.WARNING && KobaltLogger.LOG_LEVEL >= 2) {
@ -224,10 +246,10 @@ class KotlinCompiler @Inject constructor(
}
}
}
System.setProperty("kotlin.incremental.compilation", "true")
// TODO: experimental should be removed as soon as it becomes standard
System.setProperty("kotlin.incremental.compilation.experimental", "true")
//
// System.setProperty("kotlin.incremental.compilation", "true")
// // TODO: experimental should be removed as soon as it becomes standard
// System.setProperty("kotlin.incremental.compilation.experimental", "true")
val result =
if (cliArgs.noIncrementalKotlin || Kobalt.context?.internalContext?.noIncrementalKotlin ?: false) {
@ -370,7 +392,8 @@ class KotlinCompiler @Inject constructor(
* JvmCompilerPlugin#createCompilerActionInfo instead
*/
fun compile(project: Project?, context: KobaltContext?, compileDependencies: List<IClasspathDependency>,
otherClasspath: List<String>, sourceFiles: List<String>, outputDir: File, args: List<String>) : TaskResult {
otherClasspath: List<String>, sourceFiles: List<String>, outputDir: File, args: List<String>,
compilerSeparateProcess: Boolean) : TaskResult {
val executor = executors.newExecutor("KotlinCompiler", 10)
@ -396,10 +419,12 @@ class KotlinCompiler @Inject constructor(
emptyList<String>()
}
val info = CompilerActionInfo(project?.directory, dependencies, sourceFiles, listOf("kt"), outputDir, args,
friendPaths, context?.internalContext?.forceRecompile ?: false)
friendPaths, context?.internalContext?.forceRecompile ?: false, compilerSeparateProcess)
return jvmCompiler.doCompile(project, context, compilerAction, info,
if (context != null) compilerUtils.sourceCompilerFlags(project, context, info) else emptyList())
val compilerFlags =
if (context != null) compilerUtils.sourceCompilerFlags(project, context, info)
else emptyList()
return jvmCompiler.doCompile(project, context, compilerAction, info, compilerFlags)
}
}
@ -410,6 +435,7 @@ class KConfiguration @Inject constructor(val compiler: KotlinCompiler){
var output: File by Delegates.notNull()
val args = arrayListOf<String>()
var noIncrementalKotlin = false
var compilerSeparateProcess = false
fun sourceFiles(s: String) = source.add(s)
@ -424,7 +450,8 @@ class KConfiguration @Inject constructor(val compiler: KotlinCompiler){
fun compile(project: Project? = null, context: KobaltContext? = null) : TaskResult {
val saved = context?.internalContext?.noIncrementalKotlin ?: false
if (context != null) context.internalContext.noIncrementalKotlin = noIncrementalKotlin
val result = compiler.compile(project, context, dependencies, classpath, source, output, args)
val result = compiler.compile(project, context, dependencies, classpath, source, output, args,
compilerSeparateProcess)
if (context != null) context.internalContext.noIncrementalKotlin = saved
return result
}

View file

@ -83,6 +83,7 @@ class KotlinPlugin @Inject constructor(val executors: KobaltExecutors, val depen
sourceFiles(info.sourceFiles)
compilerArgs(info.compilerArgs)
output = info.outputDir
compilerSeparateProcess = info.compilerSeparateProcess
}.compile(project, context)
}

View file

@ -1 +1 @@
kobalt.version=1.0.62
kobalt.version=1.0.72