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

Getting to dex.

This commit is contained in:
Cedric Beust 2015-12-04 02:42:10 -08:00
parent 69361b1bec
commit 7e574951b2
13 changed files with 197 additions and 59 deletions

View file

@ -25,23 +25,48 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
fun toTask(taskName: String) = taskName + productFlavor.name.capitalize() + buildType.name.capitalize()
fun sourceDirectories(project: Project) : List<File> {
/**
* for {internal, release}, return [internal, release, internalRelease]
*/
fun allDirectories(project: Project): List<String> {
val result = arrayListOf<String>()
if (productFlavor != null) result.add(productFlavor.name)
if (buildType != null) result.add(buildType.name)
result.add(toCamelcaseDir())
return result
}
fun resDirectories(project: Project) : List<File> = sourceDirectories(project, "res")
fun sourceDirectories(project: Project) : List<File> =
sourceDirectories(project, project.projectInfo.sourceDirectory)
/**
* suffix is either "java" (to find source files) or "res" (to find resources)
*/
private fun sourceDirectories(project: Project, suffix: String) : List<File> {
val result = arrayListOf<File>()
val sourceDirectories = project.sourceDirectories.map { File(it) }
if (isDefault) {
result.addAll(sourceDirectories)
} else {
// The ordering of files is: 1) build type 2) product flavor 3) default
buildType.let {
val dir = File(KFiles.joinDir("src", it.name, project.projectInfo.sourceDirectory))
log(2, "Adding source for build type ${it.name}: ${dir.path}")
result.add(dir)
}
productFlavor.let {
val dir = File(KFiles.joinDir("src", it.name, project.projectInfo.sourceDirectory))
log(2, "Adding source for product flavor ${it.name}: ${dir.path}")
result.add(dir)
}
result.addAll(allDirectories(project).map {
File(KFiles.joinDir("src", it, suffix))
}.filter {
it.exists()
})
// // The ordering of files is: 1) build type 2) product flavor 3) default
// buildType.let {
// val dir = File(KFiles.joinDir("src", it.name, project.projectInfo.sourceDirectory))
// log(2, "Adding source for build type ${it.name}: ${dir.path}")
// result.add(dir)
// }
// productFlavor.let {
// val dir = File(KFiles.joinDir("src", it.name, project.projectInfo.sourceDirectory))
// log(2, "Adding source for product flavor ${it.name}: ${dir.path}")
// result.add(dir)
// }
// Now that all the variant source directories have been added, add the project's default ones
result.addAll(sourceDirectories)
@ -101,10 +126,10 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
/**
* Generate BuildConfig.java if requested. Also look up if any BuildConfig is defined on the current build type,
* product flavor or main project, and use them to generate any additional field (in that order to
* respect the priorities).
* respect the priorities). Return the generated file if it was generated, null otherwise.
*/
fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) {
fun generated(project: Project) = KFiles.joinDir(AndroidFiles.generated(project), "source")
fun maybeGenerateBuildConfig(project: Project, context: KobaltContext) : File? {
fun generated(project: Project) = AndroidFiles.generatedSourceDir(project)
val buildConfigs = findBuildConfigs(project, context.variant)
@ -115,15 +140,18 @@ class Variant(val initialProductFlavor: ProductFlavorConfig? = null,
?: throw KobaltException(
"packageName needs to be defined on the project in order to generate BuildConfig")
val code = project.projectInfo.generateBuildConfig(pkg, context.variant, buildConfigs)
val g = KFiles.makeDir(generated(project))
val code = project.projectInfo.generateBuildConfig(project, context, pkg, context.variant, buildConfigs)
val result = KFiles.makeDir(generated(project))
// Make sure the generatedSourceDirectory doesn't contain the project.directory since
// that directory will be added when trying to find recursively all the sources in it
generatedSourceDirectory = File(g.relativeTo(File(project.directory)))
val outputGeneratedSourceDirectory = File(g, pkg.replace('.', File.separatorChar))
val outputFile = File(outputGeneratedSourceDirectory, "BuildConfig" + project.sourceSuffix)
KFiles.saveFile(outputFile, code)
log(2, "Generated ${outputFile.path}")
generatedSourceDirectory = File(result.relativeTo(File(project.directory)))
val outputGeneratedSourceDirectory = File(result, pkg.replace('.', File.separatorChar))
val outputDir = File(outputGeneratedSourceDirectory, "BuildConfig" + project.sourceSuffix)
KFiles.saveFile(outputDir, code)
log(2, "Generated ${outputDir.path}")
return result
} else {
return null
}
}

View file

@ -0,0 +1,10 @@
package com.beust.kobalt.api
class BuildConfigField(val type: String, val name: String, val value: Any)
/**
* Plug-ins that want to add fields to BuildConfig need to implement this interface.
*/
interface IBuildConfigFieldContributor {
fun fieldsFor(project: Project, context: KobaltContext) : List<BuildConfigField>
}

View file

@ -0,0 +1,10 @@
package com.beust.kobalt.api
import java.io.File
/**
* Plug-ins that add source directories to be compiled need to implement this interface.
*/
interface ISourceDirectoryContributor {
fun sourceDirectoriesFor(project: Project, context: KobaltContext): List<File>
}

View file

@ -26,7 +26,7 @@ open public class Project(
@Directive open var packageName: String? = group,
val projectInfo: IProjectInfo) : IBuildConfig {
override var buildConfig: BuildConfig? = null
override var buildConfig = BuildConfig()
val testArgs = arrayListOf<String>()
val testJvmArgs = arrayListOf<String>()
@ -171,7 +171,7 @@ class BuildConfig {
}
interface IBuildConfig {
var buildConfig: BuildConfig?
var buildConfig: BuildConfig
fun buildConfig(init: BuildConfig.() -> Unit) {
buildConfig = BuildConfig().apply {
@ -181,7 +181,7 @@ interface IBuildConfig {
}
class ProductFlavorConfig(val name: String) : IBuildConfig {
override var buildConfig: BuildConfig? = null
override var buildConfig = BuildConfig()
}
@Directive
@ -199,7 +199,7 @@ class BuildTypeConfig(val project: Project?, val name: String) : IBuildConfig {
return Proguard(androidPlugin.androidHome(project)).getDefaultProguardFile(name)
}
override var buildConfig: BuildConfig? = null
override var buildConfig = BuildConfig()
}
@Directive

View file

@ -124,19 +124,25 @@ abstract class JvmCompilerPlugin @Inject constructor(
project.projectProperties.put(COMPILER_ARGS, arrayListOf(*args))
}
fun findSourceFiles(dir: String, sourceDirectories: Collection<String>): List<String> {
fun findSourceFiles(project: Project, context: KobaltContext, dir: String,
sourceDirectories: Collection<String>): List<String> {
val projectDir = File(dir)
return files.findRecursively(projectDir,
sourceDirectories.map { File(it) }) { it: String -> it.endsWith(".java") }
.map { File(projectDir, it).absolutePath }
val allSourceDirectories = arrayListOf<File>()
allSourceDirectories.addAll(sourceDirectories.map { File(it) })
context.pluginInfo.sourceDirContributors.forEach {
allSourceDirectories.addAll(it.sourceDirectoriesFor(project, context))
}
return files.findRecursively(projectDir, allSourceDirectories) {
it: String -> it.endsWith(".java")
}.map { File(projectDir, it).absolutePath }
}
override fun projects() = projects
@Task(name = JavaPlugin.TASK_COMPILE, description = "Compile the project")
fun taskCompile(project: Project) : TaskResult {
context.variant.maybeGenerateBuildConfig(project, context)
val info = createCompilerActionInfo(project, context)
val generatedDir = context.variant.maybeGenerateBuildConfig(project, context)
val info = createCompilerActionInfo(project, context, generatedDir)
val compiler = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.compilerContributors)
if (compiler != null) {
return compiler.compile(project, context, info)
@ -149,14 +155,15 @@ abstract class JvmCompilerPlugin @Inject constructor(
fun taskJavadoc(project: Project) : TaskResult {
val docGenerator = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.docContributors)
if (docGenerator != null) {
return docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context))
return docGenerator.generateDoc(project, context, createCompilerActionInfo(project, context, null))
} else {
warn("Couldn't find any doc contributor for project ${project.name}")
return TaskResult()
}
}
private fun createCompilerActionInfo(project: Project, context: KobaltContext) : CompilerActionInfo {
private fun createCompilerActionInfo(project: Project, context: KobaltContext, generatedSourceDir: File?)
: CompilerActionInfo {
copyResources(project, JvmCompilerPlugin.SOURCE_SET_MAIN)
val classpath = dependencyManager.calculateDependencies(project, context, projects,
@ -166,10 +173,26 @@ abstract class JvmCompilerPlugin @Inject constructor(
val buildDirectory = File(project.classesDir(context))
buildDirectory.mkdirs()
val initialSourceDirectories = context.variant.sourceDirectories(project)
val sourceDirectories = context.pluginInfo.sourceDirectoriesInterceptors.fold(initialSourceDirectories,
val initialSourceDirectories = arrayListOf<File>()
// Add the generated source dir if any
generatedSourceDir?.let {
initialSourceDirectories.add(it)
}
// Source directories from the project and variants
initialSourceDirectories.addAll(context.variant.sourceDirectories(project))
// Source directories from the contributors
context.pluginInfo.sourceDirContributors.forEach {
initialSourceDirectories.addAll(it.sourceDirectoriesFor(project, context))
}
// Transform them with the interceptors, if any
val sourceDirectories = context.pluginInfo.sourceDirectoriesInterceptors.fold(initialSourceDirectories.toList(),
{ sd, interceptor -> interceptor.intercept(project, context, sd) })
// Now that we have the final list of source dirs, find source files in them
val sourceFiles = files.findRecursively(projectDirectory, sourceDirectories,
{ it .endsWith(project.sourceSuffix) })
.map { File(projectDirectory, it).path }

View file

@ -70,6 +70,8 @@ class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) {
val classpathInterceptors = arrayListOf<IClasspathInterceptor>()
val compilerContributors = arrayListOf<ICompilerContributor>()
val docContributors = arrayListOf<IDocContributor>()
val sourceDirContributors = arrayListOf<ISourceDirectoryContributor>()
val buildConfigFieldContributors = arrayListOf<IBuildConfigFieldContributor>()
// Future contributors:
// source files
@ -135,6 +137,8 @@ class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) {
if (this is IClasspathInterceptor) classpathInterceptors.add(this)
if (this is ICompilerContributor) compilerContributors.add(this)
if (this is IDocContributor) docContributors.add(this)
if (this is ISourceDirectoryContributor) sourceDirContributors.add(this)
if (this is IBuildConfigFieldContributor) buildConfigFieldContributors.add(this)
}
}
}
@ -158,6 +162,8 @@ class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) {
classpathInterceptors.addAll(pluginInfo.classpathInterceptors)
compilerContributors.addAll(pluginInfo.compilerContributors)
docContributors.addAll(pluginInfo.docContributors)
sourceDirContributors.addAll(pluginInfo.sourceDirContributors)
buildConfigFieldContributors.addAll(pluginInfo.buildConfigFieldContributors)
}
}

View file

@ -2,6 +2,9 @@ package com.beust.kobalt.internal
import com.beust.kobalt.Variant
import com.beust.kobalt.api.BuildConfig
import com.beust.kobalt.api.BuildConfigField
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import java.util.*
/**
@ -18,5 +21,18 @@ interface IProjectInfo {
* If at least one build config was found either on the project or the variant, this function
* will be used to generate the BuildConfig file with the correct language.
*/
fun generateBuildConfig(packageName: String, variant: Variant, buildConfigs: List<BuildConfig>) : String
fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant,
buildConfigs: List<BuildConfig>) : String
}
interface BaseProjectInfo : IProjectInfo {
fun generate(field: BuildConfigField) : String
fun generate(type: String, name: String, value: Any) = generate(BuildConfigField(type, name, value))
fun generateFieldsFromContributors(project: Project, context: KobaltContext)
= context.pluginInfo.buildConfigFieldContributors.flatMap {
it.fieldsFor(project, context)
}.map {
generate(it)
}
}

View file

@ -141,6 +141,8 @@ class AndroidBuild {
val srcList = listOf("main", variant.productFlavor.name, variant.buildType.name, fullVariantDir.path)
.map { "src" + File.separator + it}
// TODO: figure out why the badSrcList is bad. All this information should be coming from the Variant
val badSrcList = variant.resDirectories(project).map { it.path }
val aarList = aarDependencies.map { it.path + File.separator}
(aarList + srcList).map { it + File.separator + "res" }.forEach { path ->
val set = ResourceSet(path)

View file

@ -30,12 +30,10 @@ class AndroidFiles {
/**
* Use the android home define on the project if any, otherwise use the environment variable.
*/
fun androidHomeNoThrows(project: Project?, config: AndroidConfig): String? {
fun androidHomeNoThrows(project: Project?, config: AndroidConfig?): String? {
var result = System.getenv("ANDROID_HOME")
if (project != null) {
if (config.androidHome != null) {
result = config.androidHome
}
if (project != null && config?.androidHome != null) {
result = config?.androidHome
}
return result
@ -43,5 +41,7 @@ class AndroidFiles {
fun androidHome(project: Project?, config: AndroidConfig) = androidHomeNoThrows(project, config) ?:
throw IllegalArgumentException("Neither androidHome nor \$ANDROID_HOME were defined")
fun generatedSourceDir(project: Project) = KFiles.joinDir(AndroidFiles.generated(project), "source")
}
}

View file

@ -22,7 +22,8 @@ import java.nio.file.Paths
public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, val merger: Merger,
val executors: KobaltExecutors)
: ConfigPlugin<AndroidConfig>(), IClasspathContributor, IRepoContributor, ICompilerFlagContributor,
ICompilerInterceptor, IBuildDirectoryIncerceptor, IRunnerContributor, IClasspathInterceptor {
ICompilerInterceptor, IBuildDirectoryIncerceptor, IRunnerContributor, IClasspathInterceptor,
ISourceDirectoryContributor, IBuildConfigFieldContributor {
companion object {
const val PLUGIN_NAME = "Android"
const val TASK_GENERATE_DEX = "generateDex"
@ -354,10 +355,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
// IRepoContributor
override fun reposFor(project: Project?): List<HostConfig> {
val config = configurationFor(project)
var home: String? = null
if (config != null) {
home = AndroidFiles.androidHomeNoThrows(project, config)
}
var home = AndroidFiles.androidHomeNoThrows(project, config)
return if (home != null) {
val path = Paths.get(KFiles.joinDir(home, "extras", "android", "m2repository"))
@ -426,6 +424,22 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
return result
}
private val extraSourceDirectories = arrayListOf<File>()
// ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List<File> = extraSourceDirectories
// IBuildConfigFieldContributor
override fun fieldsFor(project: Project, context: KobaltContext): List<BuildConfigField> {
val result = arrayListOf<BuildConfigField>()
configurationFor(project)?.let { config ->
result.add(BuildConfigField("String", "VERSION_NAME", "\"${config.versionName}\""))
result.add(BuildConfigField("int", "VERSION_CODE", "${config.versionCode}"))
}
return result
}
}
class AndroidConfig(val project: Project,
@ -433,6 +447,7 @@ class AndroidConfig(val project: Project,
var buildToolsVersion: String? = null,
var minSdkVersion: String? = null,
var versionCode: Int? = null,
var versionName: String? = null,
var targetSdkVersion: String? = null,
var applicationId: String? = null,
val androidHome: String? = null) {

View file

@ -68,7 +68,7 @@ class JavaPlugin @Inject constructor(
@Task(name = TASK_COMPILE_TEST, description = "Compile the tests", runAfter = arrayOf("compile"))
fun taskCompileTest(project: Project): TaskResult {
val sourceFiles = findSourceFiles(project.directory, project.sourceDirectoriesTest)
val sourceFiles = findSourceFiles(project, context, project.directory, project.sourceDirectoriesTest)
val result =
if (sourceFiles.size > 0) {
copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST)

View file

@ -2,26 +2,40 @@ package com.beust.kobalt.plugin.java
import com.beust.kobalt.Variant
import com.beust.kobalt.api.BuildConfig
import com.beust.kobalt.internal.IProjectInfo
import com.beust.kobalt.api.BuildConfigField
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.BaseProjectInfo
import com.google.inject.Singleton
@Singleton
class JavaProjectInfo : IProjectInfo {
class JavaProjectInfo : BaseProjectInfo {
override val sourceDirectory = "java"
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")
private fun generate(type: String, name: String, value: Any) =
" public static final $type $name = $value;"
override fun generate(field: BuildConfigField) = with(field) {
" public static final $type $name = $value;"
}
override fun generateBuildConfig(packageName: String, variant: Variant, buildConfigs: List<BuildConfig>) : String {
override fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant,
buildConfigs: List<BuildConfig>) : String {
val lines = arrayListOf<String>()
with(lines) {
add("package $packageName;")
add("")
add("public final class BuildConfig {")
add(generate("String", "PRODUCT_FLAVOR", "\"" + variant.productFlavor.name + "\""))
add(generate("String", "FLAVOR", "\"" + variant.productFlavor.name + "\""))
add(generate("String", "BUILD_TYPE", "\"" + variant.buildType.name + "\""))
add(generate("boolean", "DEBUG",
if (variant.productFlavor.name.equals("debug", ignoreCase = true)) {
"true"
} else {
"false"
}))
addAll(generateFieldsFromContributors(project, context))
buildConfigs.forEach {
it.fields.forEach { field ->
add(generate(field.type, field.name, field.value))

View file

@ -2,19 +2,24 @@ package com.beust.kobalt.plugin.kotlin
import com.beust.kobalt.Variant
import com.beust.kobalt.api.BuildConfig
import com.beust.kobalt.internal.IProjectInfo
import com.beust.kobalt.api.BuildConfigField
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.BaseProjectInfo
import com.google.inject.Singleton
@Singleton
class KotlinProjectInfo : IProjectInfo {
class KotlinProjectInfo : BaseProjectInfo {
override val sourceDirectory = "kotlin"
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")
private fun generate(type: String, name: String, value: Any) =
" val $name : $type = $value"
override fun generate(field: BuildConfigField) = with(field) {
" val $name : $type = $value"
}
override fun generateBuildConfig(packageName: String, variant: Variant, buildConfigs: List<BuildConfig>) : String {
override fun generateBuildConfig(project: Project, context: KobaltContext, packageName: String, variant: Variant,
buildConfigs: List<BuildConfig>) : String {
val lines = arrayListOf<String>()
with(lines) {
add("package $packageName")
@ -23,6 +28,15 @@ class KotlinProjectInfo : IProjectInfo {
add(" companion object {")
add(generate("String", "PRODUCT_FLAVOR", "\"" + variant.productFlavor.name + "\""))
add(generate("String", "BUILD_TYPE", "\"" + variant.buildType.name + "\""))
add(generate("String", "DEBUG",
if (variant.productFlavor.name.equals("debug", ignoreCase = true)) {
"true"
} else {
"false"
}))
addAll(generateFieldsFromContributors(project, context))
buildConfigs.forEach {
it.fields.forEach { field ->
add(generate(field.type, field.name, field.value))