mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 08:27:12 -07:00
Incremental packaging.
This commit is contained in:
parent
fa546e4510
commit
15b43c0127
12 changed files with 94 additions and 44 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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)
|
||||||
|
|
17
src/test/kotlin/com/beust/kobalt/misc/IncludedFileTest.kt
Normal file
17
src/test/kotlin/com/beust/kobalt/misc/IncludedFileTest.kt
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue