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

Incremental packaging.

This commit is contained in:
Cedric Beust 2015-12-22 05:45:51 +04:00
parent fa546e4510
commit 15b43c0127
12 changed files with 94 additions and 44 deletions

View file

@ -3,6 +3,6 @@ package com.beust.kobalt
class Features { class Features {
companion object { companion object {
/** If true, uses timestamps to speed up the tasks */ /** If true, uses timestamps to speed up the tasks */
const val USE_TIMESTAMPS = false const val USE_TIMESTAMPS = true
} }
} }

View file

@ -40,7 +40,7 @@ class JvmCompiler @Inject constructor(val dependencyManager: DependencyManager)
val addedFlags = contributorFlags + ArrayList(info.compilerArgs) val addedFlags = contributorFlags + ArrayList(info.compilerArgs)
validateClasspath(allDependencies.map { it.jarFile.get().absolutePath }) validateClasspath(allDependencies.map { it.jarFile.get().absolutePath })
return action.compile(info.copy(dependencies = allDependencies, compilerArgs = addedFlags)) return action.compile(project?.name, info.copy(dependencies = allDependencies, compilerArgs = addedFlags))
} }
private fun validateClasspath(cp: List<String>) { private fun validateClasspath(cp: List<String>) {
@ -53,5 +53,5 @@ class JvmCompiler @Inject constructor(val dependencyManager: DependencyManager)
} }
interface ICompilerAction { interface ICompilerAction {
fun compile(info: CompilerActionInfo): TaskResult fun compile(projectName: String?, info: CompilerActionInfo): TaskResult
} }

View file

@ -1,6 +1,5 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.Features
import com.beust.kobalt.IncrementalTaskInfo import com.beust.kobalt.IncrementalTaskInfo
import com.beust.kobalt.KobaltException import com.beust.kobalt.KobaltException
import com.beust.kobalt.TaskResult import com.beust.kobalt.TaskResult
@ -188,16 +187,11 @@ abstract class JvmCompilerPlugin @Inject constructor(
sourceDirectories.add(sourceDirectory) sourceDirectories.add(sourceDirectory)
} }
val info = createCompilerActionInfo(project, context, isTest = false) val info = createCompilerActionInfo(project, context, isTest = false)
if (! Features.USE_TIMESTAMPS || isOutdated(project, context, info)) { val compiler = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.compilerContributors)
val compiler = ActorUtils.selectAffinityActor(project, context, context.pluginInfo.compilerContributors) if (compiler != null) {
if (compiler != null) { return compiler.compile(project, context, info)
return compiler.compile(project, context, info)
} else {
throw KobaltException("Couldn't find any compiler for project ${project.name}")
}
} else { } else {
log(2, " Source files are up to date, not compiling") throw KobaltException("Couldn't find any compiler for project ${project.name}")
return TaskResult()
} }
} }

View file

@ -109,7 +109,7 @@ public class TaskManager @Inject constructor(val args: Args, val incrementalMana
graph.addEdge(pluginTask, to) graph.addEdge(pluginTask, to)
} }
} else { } else {
log(2, "Couldn't find node $it: not applicable to project ${project.name}") log(1, "Couldn't find node $it: not applicable to project ${project.name}")
} }
} }
} }
@ -206,7 +206,7 @@ public class TaskManager @Inject constructor(val args: Args, val incrementalMana
newToProcess.add(TaskInfo(project.name, it)) newToProcess.add(TaskInfo(project.name, it))
} }
} else { } else {
log(2, "Couldn't find task ${currentTask.taskName}: not applicable to project ${project.name}") log(1, "Couldn't find task ${currentTask.taskName}: not applicable to project ${project.name}")
} }
} }
done = newToProcess.isEmpty() done = newToProcess.isEmpty()
@ -256,34 +256,37 @@ public class TaskManager @Inject constructor(val args: Args, val incrementalMana
if (outputChecksum == iit.outputChecksum) { if (outputChecksum == iit.outputChecksum) {
upToDate = true upToDate = true
} else { } else {
log(2, " INC- Incremental task ${ta.name} output is out of date, running it") logIncremental(1, "Incremental task ${ta.name} output is out of date, running it")
} }
} }
} else { } else {
log(2, " INC- Incremental task ${ta.name} input is out of date, running it") logIncremental(1, "Incremental task ${ta.name} input is out of date, running it"
+ " old: $inputChecksum new: ${iit.inputChecksum}")
} }
} }
if (! upToDate) { if (! upToDate) {
val result = iit.task(project) val result = iit.task(project)
if (result.success) { if (result.success) {
log(2, " INC- Incremental task ${ta.name} done running, saving checksums") logIncremental(1, "Incremental task ${ta.name} done running, saving checksums")
iit.inputChecksum?.let { iit.inputChecksum?.let {
incrementalManager.saveInputChecksum(taskName, it) incrementalManager.saveInputChecksum(taskName, it)
log(2, " INC- input checksum \"$it\" saved") logIncremental(1, " input checksum \"$it\" saved")
} }
iit.outputChecksum?.let { iit.outputChecksum?.let {
incrementalManager.saveOutputChecksum(taskName, it) incrementalManager.saveOutputChecksum(taskName, it)
log(2, " INC- output checksum \"$it\" saved") logIncremental(1, " output checksum \"$it\" saved")
} }
} }
result result
} else { } else {
log(2, " INC- Incremental task ${ta.name} is up to date, not running it") logIncremental(2, "Incremental task \"${ta.name}\" is up to date, not running it")
TaskResult() TaskResult()
} }
}) })
private fun logIncremental(level: Int, s: String) = log(level, " INC - $s")
class PluginDynamicTask(val plugin: IPlugin, val task: DynamicTask) class PluginDynamicTask(val plugin: IPlugin, val task: DynamicTask)
/** Tasks annotated with @Task or @IncrementalTask */ /** Tasks annotated with @Task or @IncrementalTask */

View file

@ -11,15 +11,20 @@ public class Md5 {
fun toMd5Directories(directories: List<File>) : String { fun toMd5Directories(directories: List<File>) : String {
MessageDigest.getInstance("MD5").let { md5 -> MessageDigest.getInstance("MD5").let { md5 ->
directories.forEach { file -> directories.forEach { file ->
val files = KFiles.findRecursively(file) // , { f -> f.endsWith("java")}) if (file.isFile) {
log(2, " Calculating checksum of ${files.size} files") val bytes = file.readBytes()
files.map {
File(file, it)
}.filter {
it.isFile
}.forEach {
val bytes = it.readBytes()
md5.update(bytes, 0, bytes.size) md5.update(bytes, 0, bytes.size)
} else {
val files = KFiles.findRecursively(file) // , { f -> f.endsWith("java")})
log(2, " Calculating checksum of ${files.size} files in $file")
files.map {
File(file, it)
}.filter {
it.isFile
}.forEach {
val bytes = it.readBytes()
md5.update(bytes, 0, bytes.size)
}
} }
} }
val result = DatatypeConverter.printHexBinary(md5.digest()).toLowerCase() val result = DatatypeConverter.printHexBinary(md5.digest()).toLowerCase()

View file

@ -157,10 +157,10 @@ class IncludedFile(val fromOriginal: From, val toOriginal: To, val specs: List<I
"from", from, "from", from,
"to", to) "to", to)
fun allFromFiles(directory: String): List<File> { fun allFromFiles(directory: String? = null): List<File> {
val result = arrayListOf<File>() val result = arrayListOf<File>()
specs.forEach { spec -> specs.forEach { spec ->
val fullDir = KFiles.joinDir(directory, from) val fullDir = if (directory == null) from else KFiles.joinDir(directory, from)
spec.toFiles(fullDir).forEach { source -> spec.toFiles(fullDir).forEach { source ->
result.add(if (source.isAbsolute) source else File(source.path)) result.add(if (source.isAbsolute) source else File(source.path))
} }

View file

@ -22,7 +22,7 @@ import javax.tools.ToolProvider
@Singleton @Singleton
class JavaCompiler @Inject constructor(val jvmCompiler: JvmCompiler) { class JavaCompiler @Inject constructor(val jvmCompiler: JvmCompiler) {
fun compilerAction(executable: File) = object : ICompilerAction { fun compilerAction(executable: File) = object : ICompilerAction {
override fun compile(info: CompilerActionInfo): TaskResult { override fun compile(projectName: String?, info: CompilerActionInfo): TaskResult {
if (info.sourceFiles.isEmpty()) { if (info.sourceFiles.isEmpty()) {
warn("No source files to compile") warn("No source files to compile")
return TaskResult() return TaskResult()

View file

@ -26,7 +26,7 @@ import kotlin.properties.Delegates
* @since 08 03, 2015 * @since 08 03, 2015
*/ */
@Singleton @Singleton
class KotlinCompiler @Inject constructor(val localRepo : LocalRepo, class KotlinCompiler @Inject constructor(
val files: KFiles, val files: KFiles,
val dependencyManager: DependencyManager, val dependencyManager: DependencyManager,
val depFactory: DepFactory, val depFactory: DepFactory,
@ -37,7 +37,7 @@ class KotlinCompiler @Inject constructor(val localRepo : LocalRepo,
} }
val compilerAction = object: ICompilerAction { val compilerAction = object: ICompilerAction {
override fun compile(info: CompilerActionInfo): TaskResult { override fun compile(projectName: String?, info: CompilerActionInfo): TaskResult {
if (info.sourceFiles.size > 1) { if (info.sourceFiles.size > 1) {
log(1, " Compiling ${info.sourceFiles.size} files") log(1, " Compiling ${info.sourceFiles.size} files")
} }
@ -58,7 +58,7 @@ class KotlinCompiler @Inject constructor(val localRepo : LocalRepo,
*(info.compilerArgs.toTypedArray()), *(info.compilerArgs.toTypedArray()),
*(info.sourceFiles.toTypedArray()) *(info.sourceFiles.toTypedArray())
) )
val success = invokeCompiler(cp, allArgs) val success = invokeCompiler(projectName ?: "kobalt-" + Random().nextInt(), cp, allArgs)
return TaskResult(success) return TaskResult(success)
} }
@ -72,8 +72,8 @@ class KotlinCompiler @Inject constructor(val localRepo : LocalRepo,
* There are plenty of ways in which this method can break but this will be immediately * There are plenty of ways in which this method can break but this will be immediately
* apparent if it happens. * apparent if it happens.
*/ */
private fun invokeCompiler(cp: List<File>, args: Array<String>): Boolean { private fun invokeCompiler(projectName: String, cp: List<File>, args: Array<String>): Boolean {
val allArgs = listOf("-module-name", "module" + Random().nextInt()) + args val allArgs = listOf("-module-name", "project-" + projectName) + args
log(2, "Calling kotlinc " + allArgs.joinToString(" ")) log(2, "Calling kotlinc " + allArgs.joinToString(" "))
val result : Boolean = val result : Boolean =
if (true) { if (true) {

View file

@ -14,7 +14,7 @@ import java.nio.file.Paths
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
class JarGenerator @Inject constructor(val dependencyManager: DependencyManager){ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager){
fun includedFilesForJarFile(project: Project, context: KobaltContext, jar: Jar) : List<IncludedFile> { fun findIncludedFiles(project: Project, context: KobaltContext, jar: Jar) : List<IncludedFile> {
// //
// Add all the applicable files for the current project // Add all the applicable files for the current project
// //
@ -73,7 +73,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
} }
fun generateJar(project: Project, context: KobaltContext, jar: Jar) : File { fun generateJar(project: Project, context: KobaltContext, jar: Jar) : File {
val allFiles = includedFilesForJarFile(project, context, jar) val allFiles = findIncludedFiles(project, context, jar)
// //
// Generate the manifest // Generate the manifest

View file

@ -116,7 +116,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
val file = File(KFiles.joinDir(directory, root.from, relFile.path)) val file = File(KFiles.joinDir(directory, root.from, relFile.path))
if (file.isFile) { if (file.isFile) {
if (file.lastModified() > lastModified) { if (file.lastModified() > lastModified) {
log(2, " Outdated $file and $output " log(2, " TS - Outdated $file and $output "
+ Date(file.lastModified()) + " " + Date(output.lastModified())) + Date(file.lastModified()) + " " + Date(output.lastModified()))
return true return true
} }
@ -139,12 +139,43 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
super.apply(project, context) super.apply(project, context)
project.projectProperties.put(LIBS_DIR, libsDir(project)) project.projectProperties.put(LIBS_DIR, libsDir(project))
taskContributor.addVariantTasks(this, project, context, "assemble", runAfter = listOf("compile"), taskContributor.addVariantTasks(this, project, context, "assemble", runAfter = listOf("compile"),
runTask = { taskAssemble(project) }) runTask = { doTaskAssemble(project) })
} }
private fun findIncludedFiles(project: Project) : List<File> {
val inf = arrayListOf<IncludedFile>()
packages.filter { it.project.name == project.name }.forEach { pkg ->
pkg.jars.forEach { inf.addAll(jarGenerator.findIncludedFiles(pkg.project, context, it)) }
pkg.wars.forEach { inf.addAll(warGenerator.findIncludedFiles(pkg.project, context, it, projects)) }
pkg.zips.forEach { inf.addAll(zipGenerator.findIncludedFiles(pkg.project, context, it)) }
}
val result = arrayListOf<File>()
inf.map { includedFile ->
result.addAll(includedFile.allFromFiles().map {
if (it.isAbsolute) it else File(KFiles.joinDir(project.directory, includedFile.from, it.path))
})
}
result.forEach { if (! it.exists())
throw RuntimeException("Should exist $it")
}
return result
}
// @IncrementalTask(name = TASK_ASSEMBLE, description = "Package the artifacts",
// runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
// fun taskAssemble(project: Project) : IncrementalTaskInfo {
// val i = findIncludedFiles(project)
// val inputChecksum = Md5.toMd5Directories(i)
// return IncrementalTaskInfo(
// inputChecksum = inputChecksum,
// outputChecksum = "1",
// task = { project -> doTaskAssemble(project) })
// }
@Task(name = TASK_ASSEMBLE, description = "Package the artifacts", @Task(name = TASK_ASSEMBLE, description = "Package the artifacts",
runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE)) runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
fun taskAssemble(project: Project) : TaskResult { fun doTaskAssemble(project: Project) : TaskResult {
project.projectProperties.put(PACKAGES, packages) project.projectProperties.put(PACKAGES, packages)
packages.filter { it.project.name == project.name }.forEach { pkg -> packages.filter { it.project.name == project.name }.forEach { pkg ->
pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) } pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) }

View file

@ -18,7 +18,7 @@ import java.util.jar.JarOutputStream
class WarGenerator @Inject constructor(val dependencyManager: DependencyManager){ class WarGenerator @Inject constructor(val dependencyManager: DependencyManager){
fun includedFilesForJarFile(project: Project, context: KobaltContext, war: War, fun findIncludedFiles(project: Project, context: KobaltContext, war: War,
projects: List<ProjectDescription>) : List<IncludedFile> { projects: List<ProjectDescription>) : List<IncludedFile> {
// //
// src/main/web app and classes // src/main/web app and classes
@ -67,7 +67,7 @@ class WarGenerator @Inject constructor(val dependencyManager: DependencyManager)
manifest.mainAttributes.putValue(attribute.first, attribute.second) manifest.mainAttributes.putValue(attribute.first, attribute.second)
} }
val allFiles = includedFilesForJarFile(project, context, war, projects) val allFiles = findIncludedFiles(project, context, war, projects)
val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) } val jarFactory = { os: OutputStream -> JarOutputStream(os, manifest) }
return PackagingPlugin.generateArchive(project, context, war.name, ".war", allFiles, return PackagingPlugin.generateArchive(project, context, war.name, ".war", allFiles,
false /* don't expand jar files */, jarFactory) false /* don't expand jar files */, jarFactory)

View file

@ -0,0 +1,17 @@
package com.beust.kobalt.misc
import com.beust.kobalt.IFileSpec
import org.testng.Assert
import org.testng.annotations.Test
import java.io.File
@Test
class IncludedFileTest {
fun simple() {
val from = "src/main/kotlin/"
val inf = IncludedFile(From(from), To(""), listOf(IFileSpec.Glob("**.kt")))
inf.allFromFiles().map { File(from, it.path) }.forEach {
Assert.assertTrue(it.exists(), "Should exist: $it")
}
}
}