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

New android build work.

This commit is contained in:
Cedric Beust 2015-12-02 02:34:12 -08:00
parent c10acfbaf7
commit ca1eff62ce
6 changed files with 213 additions and 55 deletions

View file

@ -32,6 +32,8 @@ dependencies {
'org.jetbrains.dokka:dokka-fatjar:0.9.2', 'org.jetbrains.dokka:dokka-fatjar:0.9.2',
// "org.jetbrains.kotlin:kotlin-compiler:${kotlin_version}", // "org.jetbrains.kotlin:kotlin-compiler:${kotlin_version}",
"com.android.tools.build:builder:1.5.0",
'com.beust:jcommander:1.48', 'com.beust:jcommander:1.48',
'com.squareup.okhttp:okhttp:2.5.0', 'com.squareup.okhttp:okhttp:2.5.0',
'org.jsoup:jsoup:1.8.3', 'org.jsoup:jsoup:1.8.3',

View file

@ -128,6 +128,8 @@ private class Main @Inject constructor(
// } // }
private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>): Int { private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>): Int {
//@@
// AndroidBuild().run()
// val file = File("/Users/beust/.kobalt/repository/com/google/guava/guava/19.0-rc2/guava-19.0-rc2.pom") // val file = File("/Users/beust/.kobalt/repository/com/google/guava/guava/19.0-rc2/guava-19.0-rc2.pom")
// val md5 = Md5.toMd5(file) // val md5 = Md5.toMd5(file)
// val md52 = MessageDigest.getInstance("MD5").digest(file.readBytes()).toHexString() // val md52 = MessageDigest.getInstance("MD5").digest(file.readBytes()).toHexString()

View file

@ -0,0 +1,96 @@
package com.beust.kobalt.plugin.android
import com.android.builder.core.AndroidBuilder
import com.android.builder.core.ErrorReporter
import com.android.builder.model.SyncIssue
import com.android.builder.sdk.DefaultSdkLoader
import com.android.builder.sdk.SdkLoader
import com.android.ide.common.blame.Message
import com.android.ide.common.process.*
import com.android.ide.common.res2.MergedResourceWriter
import com.android.ide.common.res2.NoOpResourcePreprocessor
import com.android.utils.StdLogger
import com.beust.kobalt.homeDir
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log
import java.io.File
class KobaltProcessResult : ProcessResult {
override fun getExitValue(): Int {
return 0
}
override fun assertNormalExitValue(): ProcessResult? {
throw UnsupportedOperationException()
}
override fun rethrowFailure(): ProcessResult? {
throw UnsupportedOperationException()
}
}
class KobaltJavaProcessExecutor : JavaProcessExecutor {
override fun execute(javaProcessInfo: JavaProcessInfo?, processOutputHandler: ProcessOutputHandler?)
: ProcessResult? {
log(1, "Executing " + javaProcessInfo!!)
return KobaltProcessResult()
}
}
class KobaltProcessOutputHandler : BaseProcessOutputHandler() {
override fun handleOutput(processOutput: ProcessOutput) =
log(1, "AndroidBuild output" + processOutput.standardOutput)
}
class KobaltErrorReporter : ErrorReporter(ErrorReporter.EvaluationMode.STANDARD) {
override fun handleSyncError(data: String?, type: Int, msg: String?): SyncIssue? {
throw UnsupportedOperationException()
}
override fun receiveMessage(message: Message?) {
throw UnsupportedOperationException()
}
}
class ProjectLayout {
val mergeBlame: File? = null
val publicText: File? = null
}
class AndroidBuild {
val annotationsJar = File("/Users/beust/adt-bundle-mac-x86_64-20140702/sdk/tools/lib/annotations.jar")
val adb = File("/Users/beust/adt-bundle-mac-x86_64-20140702/sdk/platform-tools/adb")
fun run() {
val logger = StdLogger(StdLogger.Level.VERBOSE)
val processExecutor = DefaultProcessExecutor(logger)
val javaProcessExecutor = KobaltJavaProcessExecutor()
val sdkLoader : SdkLoader = DefaultSdkLoader.getLoader(File("/Users/beust/adt-bundle-mac-x86_64-20140702/sdk"))
val repositories = sdkLoader.repositories
val androidBuilder = AndroidBuilder("com.beust.kobalt", "Cedric Beust",
processExecutor,
javaProcessExecutor,
KobaltErrorReporter(),
StdLogger(StdLogger.Level.VERBOSE),
true /* verbose */)
val sdkInfo = androidBuilder.sdkInfo
val target = androidBuilder.target
val dxJar = androidBuilder.dxJar
val processOutputHandler = KobaltProcessOutputHandler()
val dir : String = KFiles.joinDir(homeDir("kotlin/kobalt-examples/android-flavors"))
val layout = ProjectLayout()
val preprocessor = NoOpResourcePreprocessor()
val writer = MergedResourceWriter(File(dir),
androidBuilder.getAaptCruncher(processOutputHandler),
false /* don't crunch */,
false /* don't process 9patch */,
layout.publicText,
layout.mergeBlame,
preprocessor)
println("Repositories: $repositories")
println("")
}
}

View file

@ -15,7 +15,6 @@ import com.google.inject.Inject
import com.google.inject.Singleton import com.google.inject.Singleton
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.net.URI
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
@ -98,11 +97,11 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
runBefore = arrayOf("compile"), runAfter = arrayOf("clean")) runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
fun taskGenerateRFile(project: Project): TaskResult { fun taskGenerateRFile(project: Project): TaskResult {
merger.merge(project, context)
val intermediates = AndroidFiles.intermediates(project) val intermediates = AndroidFiles.intermediates(project)
val resDir = "temporaryBogusResDir" val resDir = AndroidFiles.mergedResources(project, context.variant)
explodeAarFiles(project, intermediates, File(resDir)) val explodedLocations = explodeAarFiles(project, intermediates)
merger.merge(project, context, explodedLocations)
val generated = AndroidFiles.generated(project) val generated = AndroidFiles.generated(project)
val success = generateR(project, generated, aapt(project)) val success = generateR(project, generated, aapt(project))
return TaskResult(success) return TaskResult(success)
@ -166,7 +165,8 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
* Extract all the .aar files found in the dependencies and add the android.jar to classpathEntries, * Extract all the .aar files found in the dependencies and add the android.jar to classpathEntries,
* which will be added to the classpath at compile time * which will be added to the classpath at compile time
*/ */
private fun explodeAarFiles(project: Project, outputDir: String, resDir: File) { private fun explodeAarFiles(project: Project, outputDir: String) : List<File> {
val result = arrayListOf<File>()
project.compileDependencies.filter { project.compileDependencies.filter {
it.jarFile.get().name.endsWith(".aar") it.jarFile.get().name.endsWith(".aar")
}.forEach { }.forEach {
@ -189,10 +189,9 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
} }
} }
// Copy all the resources from this aar into the same intermediate directory result.add(destDir)
log(2, "Copying the resources to $resDir")
KFiles.copyRecursively(destDir.resolve("res"), resDir, deleteFirst = false)
} }
return result
} }
private fun compile(project: Project, rDirectory: String): File { private fun compile(project: Project, rDirectory: String): File {
@ -350,10 +349,11 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
} }
// IRepoContributor // IRepoContributor
override fun reposFor(project: Project?): List<URI> { override fun reposFor(project: Project?): List<HostInfo> {
val home = androidHomeNoThrows(project) val home = androidHomeNoThrows(project)
return if (home != null) { return if (home != null) {
listOf(Paths.get(KFiles.joinDir(home, "extras", "android", "m2repository")).toUri()) val uri = Paths.get(KFiles.joinDir(home, "extras", "android", "m2repository")).toUri()
listOf(HostInfo(uri.toString()))
} else { } else {
emptyList() emptyList()
} }

View file

@ -1,17 +1,18 @@
package com.beust.kobalt.plugin.android package com.beust.kobalt.plugin.android
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Variant import com.beust.kobalt.Variant
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.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.log import com.beust.kobalt.misc.log
import com.google.inject.Inject import com.google.inject.Inject
import java.io.* import java.io.File
import java.io.InputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import java.util.* import java.util.*
import javax.xml.bind.JAXBContext import javax.xml.bind.JAXBContext
import javax.xml.bind.Marshaller
import javax.xml.bind.annotation.XmlAttribute import javax.xml.bind.annotation.XmlAttribute
import javax.xml.bind.annotation.XmlElement import javax.xml.bind.annotation.XmlElement
import javax.xml.bind.annotation.XmlRootElement import javax.xml.bind.annotation.XmlRootElement
@ -21,17 +22,17 @@ import javax.xml.bind.annotation.XmlValue
* Merges manifests and resources. * Merges manifests and resources.
*/ */
class Merger @Inject constructor() { class Merger @Inject constructor() {
fun merge(project: Project, context: KobaltContext) { fun merge(project: Project, context: KobaltContext, explodedLocations: List<File>) {
File(AndroidFiles.mergedResourcesNoVariant(project)).deleteRecursively() File(AndroidFiles.mergedResourcesNoVariant(project)).deleteRecursively()
mergeResources(project, context.variant) mergeResources(project, context.variant, explodedLocations)
mergeAndroidManifest(project, context.variant) mergeAndroidManifest(project, context.variant, explodedLocations)
log(2, "All done merging") log(2, "All done merging")
} }
/** /**
* TODO: not implemented yet, just copying the manifest to where the merged manifest should be. * TODO: not implemented yet, just copying the manifest to where the merged manifest should be.
*/ */
private fun mergeAndroidManifest(project: Project, variant: Variant) { private fun mergeAndroidManifest(project: Project, variant: Variant, explodedLocations: List<File>) {
val dest = AndroidFiles.mergedManifest(project, variant) val dest = AndroidFiles.mergedManifest(project, variant)
log(2, "----- Merging manifest (not implemented, copying it to $dest)") log(2, "----- Merging manifest (not implemented, copying it to $dest)")
KFiles.copy(Paths.get(project.directory, "src/main/AndroidManifest.xml"), Paths.get(dest)) KFiles.copy(Paths.get(project.directory, "src/main/AndroidManifest.xml"), Paths.get(dest))
@ -42,43 +43,91 @@ class Merger @Inject constructor() {
fun doMerge(fromFile: File, toFile: File) fun doMerge(fromFile: File, toFile: File)
} }
/** class ValueFile(file: File) {
* Merge files found in values/, e.g. values/strings.xml. private var header = ""
* All the files are enumerated for each one, look if a file by the same name is present in the merged private var footer = ""
* directory. If not, copy it. If there is, look for a merger for this file and run it. private val lines = arrayListOf<String>()
*/ private val lineSet = hashSetOf<String>()
class ValuesFileMerger : IFileMerger {
override fun canMerge(fromFile: File, toFile: File) : Boolean { init {
return fromFile.parentFile.name == "values" file.forEachLine { line ->
if (line.contains("<resources>") && header.isNullOrBlank()) {
lineSet.add(line)
header = line
} else if (line.contains("</resources>") && footer.isNullOrBlank()) {
lineSet.add(line)
footer = line
} else {
if (footer.isNullOrBlank()) {
lines.add(line)
lineSet.add(line)
} else {
throw KobaltException("Extra text after the footer")
}
}
}
} }
override fun doMerge(fromFile: File, toFile: File) { fun merge(file: File) : ValueFile {
FileInputStream(toFile).use { toInputStream -> fun log(s: String) {
val toXml = readValuesXml(toInputStream) log(3, " Merge(${file.name}): $s")
FileInputStream(fromFile).use { fromInputStream ->
val fromXml = readValuesXml(fromInputStream)
val seen = toXml.strings.map { it.name!! }.toHashSet<String>()
fromXml.strings.forEach {
if (!seen.contains(it.name!!)) {
log(3, " Unconflicted string: ${it.name}")
toXml.strings.add(it)
} else {
log(3, " String ${it.name} already present, ignoring")
}
}
}
val mergedText = StringWriter()
val pw = PrintWriter(mergedText)
JAXBContext.newInstance(ValuesXml::class.java).createMarshaller().let { marshaller ->
with(marshaller) {
setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)
setProperty(Marshaller.JAXB_ENCODING, "UTF-8")
marshal(toXml, pw)
}
}
KFiles.saveFile(toFile, mergedText.toString())
} }
file.forEachLine { line ->
if (! lineSet.contains(line)) {
lines.add(line)
lineSet.add(line)
log("Unconflicted: $line")
} else {
log("Already present, ignoring: $line")
}
}
return this
}
fun toXml() = (listOf(header) + lines + listOf(footer)).joinToString("\n")
}
/**
* Merge files found in values/, e.g. values/strings.xml.
* All the files are enumerated. If a file by the same name is present in the merged
* directory, merge it. Otherwise, copy it.
*/
class ValuesFileMerger : IFileMerger {
override fun canMerge(fromFile: File, toFile: File) = fromFile.parentFile.name == "values"
override fun doMerge(fromFile: File, toFile: File) {
if (toFile.path.endsWith("values.xml")) {
println("DONOTCOMMIT VALUES.XML")
}
val mergedXml = ValueFile(fromFile).merge(toFile).toXml()
KFiles.saveFile(toFile, mergedXml.toString())
// FileInputStream(toFile).use { toInputStream ->
// val toXml = readValuesXml(toInputStream)
// FileInputStream(fromFile).use { fromInputStream ->
// val fromXml = readValuesXml(fromInputStream)
// val seen = toXml.strings.map { it.name!! }.toHashSet<String>()
// fromXml.strings.forEach {
// if (!seen.contains(it.name!!)) {
// log(3, " Unconflicted string: ${it.name}")
// toXml.strings.add(it)
// } else {
// log(3, " String ${it.name} already present, ignoring")
// }
// }
// }
// val mergedText = StringWriter()
// val pw = PrintWriter(mergedText)
//
// JAXBContext.newInstance(ValuesXml::class.java).createMarshaller().let { marshaller ->
// with(marshaller) {
// setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)
// setProperty(Marshaller.JAXB_ENCODING, "UTF-8")
// marshal(toXml, pw)
// }
// }
// KFiles.saveFile(toFile, mergedText.toString())
// }
} }
@ -109,13 +158,18 @@ class Merger @Inject constructor() {
/** /**
* Spec: http://developer.android.com/sdk/installing/studio-build.html * Spec: http://developer.android.com/sdk/installing/studio-build.html
*/ */
private fun mergeResources(project: Project, variant: Variant) { private fun mergeResources(project: Project, variant: Variant, explodedLocations: List<File>) {
val dest = AndroidFiles.Companion.mergedResources(project, variant) val dest = AndroidFiles.Companion.mergedResources(project, variant)
log(2, "----- Merging res/ directory to $dest") log(2, "----- Merging res/ directory to $dest")
listOf(variant.buildType.name, variant.productFlavor.name, "main").forEach { val srcFromDirs = listOf(variant.buildType.name, variant.productFlavor.name, "main").map {
log(3, " Current variant: $it") File(project.directory, "src/$it/res")
}
val fromDir = File(project.directory, "src/$it/res") val fromDirs = explodedLocations.map { File(it, "res") } + srcFromDirs
// listOf(variant.buildType.name, variant.productFlavor.name, "main").forEach {
// log(3, " Current variant: $it")
//
// val fromDir = File(project.directory, "src/$it/res")
fromDirs.filter { it.exists() }.forEach { fromDir ->
KFiles.findRecursively(fromDir).forEach { KFiles.findRecursively(fromDir).forEach {
val fromFile = File(fromDir, it) val fromFile = File(fromDir, it)
val toFile = File(dest, it) val toFile = File(dest, it)
@ -131,6 +185,7 @@ class Merger @Inject constructor() {
} }
} }
println("DONE MERGING")
} }
} }

View file

@ -0,0 +1,3 @@
package com.beust.kobalt.plugin.android
//import com.android.builder.dependency.LibraryDependency