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

Mixed language projects.

This commit is contained in:
Cedric Beust 2016-02-02 22:58:53 +04:00
parent 93415868b0
commit b474c2de37
11 changed files with 73 additions and 66 deletions

View file

@ -1,6 +1,7 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.internal.ActorUtils
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log import com.beust.kobalt.misc.log
import java.io.File import java.io.File
@ -34,11 +35,14 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
return result return result
} }
fun resDirectories(project: Project) : List<File> = sourceDirectories(project, "res") fun sourceDirectories(project: Project, context: KobaltContext) : List<File> {
val compilers = ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors)
fun sourceDirectories(project: Project) = project.projectInfo.sourceSuffixes.flatMap { val sourceSuffixes = compilers.flatMap { it.sourceSuffixes }
val result = sourceSuffixes.flatMap {
sourceDirectories(project, it) sourceDirectories(project, it)
} }.toHashSet()
return result.toList()
}
/** /**
* suffix is either "java" (to find source files) or "res" (to find resources) * suffix is either "java" (to find source files) or "res" (to find resources)
@ -141,7 +145,9 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
// that directory will be added when trying to find recursively all the sources in it // that directory will be added when trying to find recursively all the sources in it
generatedSourceDirectory = File(result.relativeTo(File(project.directory))) generatedSourceDirectory = File(result.relativeTo(File(project.directory)))
val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar)) val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar))
val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig" + project.sourceSuffix) val compilers = ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors)
val outputDir = File(outputGeneratedSourceDirectory,
"BuildConfig" + compilers[0].sourceSuffixes[0])
KFiles.saveFile(outputDir, code) KFiles.saveFile(outputDir, code)
log(2, "Generated ${outputDir.path}") log(2, "Generated ${outputDir.path}")
return result return result

View file

@ -1,9 +1,8 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.TaskResult import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.IClasspathDependency
import java.io.File
interface ICompilerContributor : IProjectAffinity { interface ICompilerContributor : IProjectAffinity {
val sourceSuffixes: List<String>
fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo) : TaskResult fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo) : TaskResult
} }

View file

@ -16,7 +16,6 @@ open class Project(
@Directive open var artifactId: String? = null, @Directive open var artifactId: String? = null,
@Directive open var packaging: String? = null, @Directive open var packaging: String? = null,
@Directive open var dependencies: Dependencies? = null, @Directive open var dependencies: Dependencies? = null,
@Directive open var sourceSuffix : String = "",
@Directive open var description : String = "", @Directive open var description : String = "",
@Directive open var scm : Scm? = null, @Directive open var scm : Scm? = null,
@Directive open var url: String? = null, @Directive open var url: String? = null,

View file

@ -13,6 +13,13 @@ class ActorUtils {
fun <T : IProjectAffinity> selectAffinityActor(project: Project, context: KobaltContext, actors: List<T>) fun <T : IProjectAffinity> selectAffinityActor(project: Project, context: KobaltContext, actors: List<T>)
= actors.maxBy { it.affinity(project, context) } = actors.maxBy { it.affinity(project, context) }
/**
* Return all the plug-in actors with a non zero affinity sorted from the highest to the lowest.
*/
fun <T : IProjectAffinity> selectAffinityActors(project: Project, context: KobaltContext, actors: List<T>)
= actors.filter { it.affinity(project, context) > 0 }
.sortedByDescending { it.affinity(project, context) }
/** /**
* Return the plug-in actor with the highest affinity. * Return the plug-in actor with the highest affinity.
*/ */

View file

@ -138,34 +138,6 @@ abstract class JvmCompilerPlugin @Inject constructor(
project.projectProperties.put(COMPILER_ARGS, arrayListOf(*args)) project.projectProperties.put(COMPILER_ARGS, arrayListOf(*args))
} }
fun isOutdated(project: Project, context: KobaltContext, actionInfo: CompilerActionInfo): Boolean {
fun stripSourceDir(sourceFile: String): String {
project.sourceDirectories.forEach {
val d = listOf(project.directory, it).joinToString("/")
if (sourceFile.startsWith(d)) return sourceFile.substring(d.length + 1)
}
throw KobaltException("Couldn't strip source dir from $sourceFile")
}
fun stripSuffix(sourceFile: String): String {
val index = sourceFile.indexOf(project.sourceSuffix)
if (index >= 0) return sourceFile.substring(0, index)
else return sourceFile
}
actionInfo.sourceFiles.map { it.replace("\\", "/") }.forEach { sourceFile ->
val stripped = stripSourceDir(sourceFile)
val classFile = File(KFiles.joinDir(project.directory, project.classesDir(context),
toClassFile(stripSuffix(stripped))))
if (!classFile.exists() || File(sourceFile).lastModified() > classFile.lastModified()) {
log(2, "Outdated $sourceFile $classFile " + Date(File(sourceFile).lastModified()) +
" " + classFile.lastModified())
return true
}
}
return false
}
@IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project") @IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project")
fun taskCompile(project: Project): IncrementalTaskInfo { fun taskCompile(project: Project): IncrementalTaskInfo {
val inputChecksum = Md5.toMd5Directories(project.sourceDirectories.map { val inputChecksum = Md5.toMd5Directories(project.sourceDirectories.map {
@ -182,18 +154,32 @@ abstract class JvmCompilerPlugin @Inject constructor(
private fun doTaskCompile(project: Project): TaskResult { private fun doTaskCompile(project: Project): TaskResult {
// Set up the source files now that we have the variant // Set up the source files now that we have the variant
sourceDirectories.addAll(context.variant.sourceDirectories(project)) sourceDirectories.addAll(context.variant.sourceDirectories(project, context))
val sourceDirectory = context.variant.maybeGenerateBuildConfig(project, context) val sourceDirectory = context.variant.maybeGenerateBuildConfig(project, context)
if (sourceDirectory != null) { if (sourceDirectory != null) {
sourceDirectories.add(sourceDirectory) sourceDirectories.add(sourceDirectory)
} }
val info = createCompilerActionInfo(project, context, isTest = false) // val info = createCompilerActionInfo(project, context, isTest = false)
val compiler = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.compilerContributors) // val compiler = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.compilerContributors)
if (compiler != null) { val results = arrayListOf<TaskResult>()
return compiler.compile(project, context, info) val compilers = ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors)
} else {
var failedResult: TaskResult? = null
if (compilers.isEmpty()) {
throw KobaltException("Couldn't find any compiler for project ${project.name}") throw KobaltException("Couldn't find any compiler for project ${project.name}")
} else {
compilers.forEach { compiler ->
val info = createCompilerActionInfo(project, context, isTest = false,
sourceSuffixes = compiler.sourceSuffixes)
val thisResult = compiler.compile(project, context, info)
results.add(thisResult)
if (! thisResult.success && failedResult == null) {
failedResult = thisResult
}
}
return if (failedResult != null) failedResult!!
else results[0]
} }
} }
@ -214,8 +200,13 @@ abstract class JvmCompilerPlugin @Inject constructor(
fun taskJavadoc(project: Project): TaskResult { fun taskJavadoc(project: Project): TaskResult {
val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors) val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors)
if (docGenerator != null) { if (docGenerator != null) {
return docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context, val compilers = ActorUtils.selectAffinityActors(project, context, context.pluginInfo.compilerContributors)
isTest = false)) var result: TaskResult? = null
compilers.forEach { compiler ->
result = docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context,
isTest = false, sourceSuffixes = compiler.sourceSuffixes))
}
return result!!
} else { } else {
warn("Couldn't find any doc contributor for project ${project.name}") warn("Couldn't find any doc contributor for project ${project.name}")
return TaskResult() return TaskResult()
@ -234,8 +225,8 @@ abstract class JvmCompilerPlugin @Inject constructor(
* Create a CompilerActionInfo (all the information that a compiler needs to know) for the given parameters. * 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. * Runs all the contributors and interceptors relevant to that task.
*/ */
protected fun createCompilerActionInfo(project: Project, context: KobaltContext, isTest: Boolean): protected fun createCompilerActionInfo(project: Project, context: KobaltContext, isTest: Boolean,
CompilerActionInfo { sourceSuffixes: List<String>): CompilerActionInfo {
copyResources(project, JvmCompilerPlugin.SOURCE_SET_MAIN) copyResources(project, JvmCompilerPlugin.SOURCE_SET_MAIN)
val fullClasspath = if (isTest) dependencyManager.testDependencies(project, context) val fullClasspath = if (isTest) dependencyManager.testDependencies(project, context)
@ -271,14 +262,23 @@ abstract class JvmCompilerPlugin @Inject constructor(
File(project.directory, it.path).exists() File(project.directory, it.path).exists()
} }
// Now that we have the final list of source dirs, find source files in them
val sourceFiles = files.findRecursively(projectDirectory, sourceDirectories, val sourceFiles = files.findRecursively(projectDirectory, sourceDirectories,
{ it.endsWith(project.sourceSuffix) }) { file -> sourceSuffixes.any { file.endsWith(it) }})
.map { File(projectDirectory, it).path } .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
val extraSourceFiles = arrayListOf<String>()
if (sourceSuffixes.any { it.contains("kt")}) {
project.sourceDirectories.forEach {
if (it.contains("java")) extraSourceFiles.add(it)
}
}
// Finally, alter the info with the compiler interceptors before returning it // Finally, alter the info with the compiler interceptors before returning it
val initialActionInfo = CompilerActionInfo(projectDirectory.path, classpath, sourceFiles, buildDirectory, val initialActionInfo = CompilerActionInfo(projectDirectory.path, classpath, sourceFiles + extraSourceFiles,
emptyList()) buildDirectory, emptyList())
val result = context.pluginInfo.compilerInterceptors.fold(initialActionInfo, { ai, interceptor -> val result = context.pluginInfo.compilerInterceptors.fold(initialActionInfo, { ai, interceptor ->
interceptor.intercept(project, context, ai) interceptor.intercept(project, context, ai)
}) })

View file

@ -7,16 +7,10 @@ import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import java.util.* import java.util.*
class LanguageInfo(val name: String, val suffix : String = name)
/** /**
* Data that is useful for projects to have but should not be specified in the DSL. * Data that is useful for projects to have but should not be specified in the DSL.
*/ */
interface IProjectInfo { interface IProjectInfo {
val languageInfos: List<LanguageInfo>
val sourceSuffixes: List<String>
val defaultSourceDirectories: HashSet<String> val defaultSourceDirectories: HashSet<String>
val defaultTestDirectories: HashSet<String> val defaultTestDirectories: HashSet<String>
@ -40,11 +34,9 @@ interface IProjectInfo {
fun dependsOnDirtyProjects(project: Project) = project.projectInfo.dependsOn.any { it.projectInfo.isDirty } fun dependsOnDirtyProjects(project: Project) = project.projectInfo.dependsOn.any { it.projectInfo.isDirty }
} }
abstract class BaseProjectInfo(override val languageInfos: List<LanguageInfo>) : IProjectInfo { abstract class BaseProjectInfo : IProjectInfo {
abstract fun generate(field: BuildConfigField) : String abstract fun generate(field: BuildConfigField) : String
override val sourceSuffixes = languageInfos.map { it.suffix }
fun generate(type: String, name: String, value: Any) = generate(BuildConfigField(type, name, value)) fun generate(type: String, name: String, value: Any) = generate(BuildConfigField(type, name, value))
fun generateFieldsFromContributors(project: Project, context: KobaltContext) fun generateFieldsFromContributors(project: Project, context: KobaltContext)

View file

@ -52,12 +52,15 @@ class JavaPlugin @Inject constructor(
override fun doTaskCompileTest(project: Project): TaskResult { override fun doTaskCompileTest(project: Project): TaskResult {
copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST) copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST)
val compilerActionInfo = createCompilerActionInfo(project, context, isTest = true) val compilerActionInfo = createCompilerActionInfo(project, context, isTest = true,
sourceSuffixes = sourceSuffixes)
val result = javaCompiler.compile(project, context, compilerActionInfo) val result = javaCompiler.compile(project, context, compilerActionInfo)
return result return result
} }
// ICompilerContributor // ICompilerContributor
override val sourceSuffixes = listOf("java")
override fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo) : TaskResult { override fun compile(project: Project, context: KobaltContext, info: CompilerActionInfo) : TaskResult {
val result = val result =
if (info.sourceFiles.size > 0) { if (info.sourceFiles.size > 0) {

View file

@ -6,11 +6,10 @@ import com.beust.kobalt.api.BuildConfigField
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.BaseProjectInfo import com.beust.kobalt.internal.BaseProjectInfo
import com.beust.kobalt.internal.LanguageInfo
import com.google.inject.Singleton import com.google.inject.Singleton
@Singleton @Singleton
class JavaProjectInfo : BaseProjectInfo(listOf(LanguageInfo("java", "java"))) { class JavaProjectInfo : BaseProjectInfo() {
override val defaultSourceDirectories = hashSetOf("src/main/java", "src/main/resources", "src/main/res") override val defaultSourceDirectories = hashSetOf("src/main/java", "src/main/resources", "src/main/res")
override val defaultTestDirectories = hashSetOf("src/test/java", "src/test/resources", "src/test/res") override val defaultTestDirectories = hashSetOf("src/test/java", "src/test/resources", "src/test/res")

View file

@ -76,8 +76,9 @@ class KotlinPlugin @Inject constructor(
copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST) copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST)
val projectDir = File(project.directory) val projectDir = File(project.directory)
val sourceFiles = files.findRecursively(projectDir, project.sourceDirectoriesTest.map { File(it) }) val sourceFiles = files.findRecursively(projectDir, project.sourceDirectoriesTest.map { File(it) })
{ it: String -> it.endsWith(project.sourceSuffix) } { file: String -> sourceSuffixes.any { file.endsWith(it) } }
.map { File(projectDir, it).absolutePath } .map { File(projectDir, it).absolutePath }
val result = val result =
@ -124,6 +125,8 @@ class KotlinPlugin @Inject constructor(
// ICompilerContributor // ICompilerContributor
override val sourceSuffixes = listOf("kt")
override fun affinity(project: Project, context: KobaltContext) = override fun affinity(project: Project, context: KobaltContext) =
if (project.sourceDirectories.any { it.contains("kotlin") }) 2 else 0 if (project.sourceDirectories.any { it.contains("kotlin") }) 2 else 0

View file

@ -6,11 +6,10 @@ import com.beust.kobalt.api.BuildConfigField
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.BaseProjectInfo import com.beust.kobalt.internal.BaseProjectInfo
import com.beust.kobalt.internal.LanguageInfo
import com.google.inject.Singleton import com.google.inject.Singleton
@Singleton @Singleton
class KotlinProjectInfo : BaseProjectInfo(listOf(LanguageInfo("kotlin", "kt"))) { class KotlinProjectInfo : BaseProjectInfo() {
override val defaultSourceDirectories = hashSetOf("src/main/kotlin", "src/main/resources", "src/main/res") override val defaultSourceDirectories = hashSetOf("src/main/kotlin", "src/main/resources", "src/main/res")
override val defaultTestDirectories = hashSetOf("src/test/kotlin", "src/test/resources", "src/test/res") override val defaultTestDirectories = hashSetOf("src/test/kotlin", "src/test/resources", "src/test/res")

View file

@ -276,7 +276,7 @@ class PackageConfig(val project: Project) : AttributeHolder {
jar { jar {
name = "${project.name}-${project.version}-sources.jar" name = "${project.name}-${project.version}-sources.jar"
project.sourceDirectories.forEach { project.sourceDirectories.forEach {
include(from(it), to(""), glob("**${project.sourceSuffix}")) include(from(it), to(""), glob("src/**"))
} }
} }
jar { jar {