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

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Erik C. Thauvin 2017-03-27 21:53:40 -07:00
commit 726ddc37d5
22 changed files with 354 additions and 491 deletions

3
.gitignore vendored
View file

@ -2,13 +2,12 @@
annotations annotations
.idea/* .idea/*
*.iml *.iml
buildScript nonBuildScript
kobaltBuild kobaltBuild
local.properties local.properties
classes classes
libs libs
.kobalt/ .kobalt/
./build/
out out
.DS_Store .DS_Store
lib/kotlin-* lib/kotlin-*

View file

@ -1 +1 @@
kobalt.version=1.0.30 kobalt.version=1.0.32

View file

@ -32,17 +32,15 @@ class ParallelLogger @Inject constructor(val args: Args) : ILogger {
val newLine: Boolean) val newLine: Boolean)
private val logLines = ConcurrentHashMap<CharSequence, ArrayList<LogLine>>() private val logLines = ConcurrentHashMap<CharSequence, ArrayList<LogLine>>()
private val runningProjects = ConcurrentLinkedQueue<CharSequence>() private val runningProjects = ConcurrentLinkedQueue<String>()
var startTime: Long? = null var startTime: Long? = null
fun onProjectStarted(name: String) { fun onProjectStarted(name: String) {
if (startTime == null) { if (startTime == null) {
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
} }
if (! runningProjects.contains(name)) { runningProjects.add(name)
runningProjects.add(name) logLines[name] = arrayListOf()
logLines[name] = arrayListOf()
}
if (currentName == null) { if (currentName == null) {
currentName = name currentName = name
} }
@ -76,7 +74,7 @@ class ParallelLogger @Inject constructor(val args: Args) : ILogger {
} }
val LOCK = Any() val LOCK = Any()
var currentName: CharSequence? = null var currentName: String? = null
set(newName) { set(newName) {
field = newName field = newName
} }
@ -121,9 +119,6 @@ class ParallelLogger @Inject constructor(val args: Args) : ILogger {
if (args.sequential) { if (args.sequential) {
kobaltLog(level, message, newLine) kobaltLog(level, message, newLine)
} else { } else {
if (! runningProjects.contains(tag)) {
runningProjects.add(tag)
}
addLogLine(tag, LogLine(tag, level, message, Type.LOG, newLine)) addLogLine(tag, LogLine(tag, level, message, Type.LOG, newLine))
} }
} }

View file

@ -1,10 +1,8 @@
package com.beust.kobalt.internal.build package com.beust.kobalt.internal.build
import com.beust.kobalt.misc.KFiles
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.attribute.BasicFileAttributes
/** /**
* Sometimes, build files are moved to temporary files, so we give them a specific name for clarity. * Sometimes, build files are moved to temporary files, so we give them a specific name for clarity.
* @param path is the path where that file was moved, @param realPath is where the actual file is. * @param path is the path where that file was moved, @param realPath is where the actual file is.
@ -12,23 +10,5 @@ import java.nio.file.attribute.BasicFileAttributes
class BuildFile(val path: Path, val name: String, val realPath: Path = path) { class BuildFile(val path: Path, val name: String, val realPath: Path = path) {
fun exists() : Boolean = Files.exists(path) fun exists() : Boolean = Files.exists(path)
val lastModified : Long
get() = Files.readAttributes(realPath, BasicFileAttributes::class.java).lastModifiedTime().toMillis()
val directory : File get() = path.toFile().parentFile val directory : File get() = path.toFile().parentFile
/**
* @return the .kobalt directory where this build file will be compiled.
*/
val dotKobaltDir: File get() = File(directory.parentFile.parentFile, KFiles.KOBALT_DOT_DIR).apply {
mkdirs()
}
/**
* @return the absolute directory of this project's location, assuming the build file is in
* $project/kobalt/src/Build.kt.
*/
val absoluteDir : File? get() {
return path.parent?.parent?.parent?.toFile()
}
} }

View file

@ -0,0 +1,57 @@
package com.beust.kobalt.internal.build
import com.beust.kobalt.homeDir
import java.io.File
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
interface IBuildSources {
fun findSourceFiles() : List<File>
val root: File
fun exists(): Boolean
}
class SingleFileBuildSources(val file: File) : IBuildSources {
override fun exists() = file.exists()
override fun findSourceFiles() = listOf(file)
override val root: File = file.parentFile.parentFile
}
class BuildSources(val file: File) : IBuildSources {
override val root = file
override fun findSourceFiles() : List<File> {
return listOf(/* "kobalt/src/a.kt", */ "kobalt/src/Build.kt")
.map(::File)
// .map { BuildFile(Paths.get(it), it)}
}
override fun exists() = findSourceFiles().isNotEmpty()
override fun toString() = "{BuildSources " + findSourceFiles()[0] + "...}"
fun _findSourceFiles() : List<File> {
val result = arrayListOf<File>()
Files.walkFileTree(Paths.get(file.absolutePath), object : SimpleFileVisitor<Path>() {
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
if (dir != null) {
val path = dir.toFile()
println(path.name)
if (path.name == "src" && path.parentFile.name == "kobalt") {
val sources = path.listFiles().filter { it.name.endsWith(".kt")}
result.addAll(sources)
}
}
return FileVisitResult.CONTINUE
}
})
return result
}
}
fun main(args: Array<String>) {
val sources = BuildSources(File(homeDir("kotlin/kobalt"))).findSourceFiles()
println("sources: " + sources)
}

View file

@ -1,14 +0,0 @@
package com.beust.kobalt.internal.remote
import com.beust.kobalt.Constants
import java.io.PrintWriter
import java.net.Socket
fun main(argv: Array<String>) {
Socket("localhost", 1234).use { socket ->
(PrintWriter(socket.outputStream, true)).use { out ->
out.println("""{ "name" : "getDependencies", "buildFile":
"/Users/beust/kotlin/kobalt/kobalt/src/${Constants.BUILD_FILE_NAME}"}""")
}
}
}

View file

@ -10,7 +10,18 @@ fun main(argv: Array<String>) {
// BlockExtractor("plugins", '(', ')').extractBlock(lines) // BlockExtractor("plugins", '(', ')').extractBlock(lines)
} }
class BuildScriptInfo(val content: String, val startLine: Int, val endLine: Int) class Section(val start: Int, val end: Int) {
override fun toString() = "$start-$end"
}
class BuildScriptInfo(val content: String, val sections: List<Section>) {
fun isInSection(lineNumber: Int): Boolean {
sections.forEach {
if (lineNumber >= it.start && lineNumber <= it.end) return true
}
return false
}
}
/** /**
* Used to extract a keyword followed by opening and closing tags out of a list of strings, * Used to extract a keyword followed by opening and closing tags out of a list of strings,
@ -26,7 +37,7 @@ class BlockExtractor(val regexp: Pattern, val opening: Char, val closing: Char)
var foundKeyword = false var foundKeyword = false
var foundClosing = false var foundClosing = false
var count = 0 var count = 0
val result = StringBuffer() val buildScript = arrayListOf<String>()
val topLines = arrayListOf<String>() val topLines = arrayListOf<String>()
fun updateCount(line: String) { fun updateCount(line: String) {
@ -46,9 +57,13 @@ class BlockExtractor(val regexp: Pattern, val opening: Char, val closing: Char)
if (foundKeyword && count > 0) currentLine.append(c) if (foundKeyword && count > 0) currentLine.append(c)
} }
if (currentLine.isNotEmpty()) result.append(currentLine.toString()).append("\n") if (currentLine.isNotEmpty() && foundKeyword) buildScript.add(currentLine.toString())
} }
val allowedImports = listOf("com.beust", "java")
val disallowedImports = listOf("com.beust.kobalt.plugin")
val imports = arrayListOf<String>()
val sections = arrayListOf<Section>()
lines.forEach { line -> lines.forEach { line ->
currentLineNumber++ currentLineNumber++
val found = regexp.matcher(line).matches() val found = regexp.matcher(line).matches()
@ -56,26 +71,33 @@ class BlockExtractor(val regexp: Pattern, val opening: Char, val closing: Char)
startLine = currentLineNumber startLine = currentLineNumber
foundKeyword = true foundKeyword = true
count = 1 count = 1
result.append(topLines.joinToString("\n")).append("\n") buildScript.add(line)
result.append(line).append("\n") topLines.add(line)
} else { } else {
val allowedImports = listOf("com.beust", "java") if (line.startsWith("import")) {
val disallowedImports = listOf("com.beust.kobalt.plugin") if (allowedImports.any { line.contains(it) } && !disallowedImports.any { line.contains(it) }) {
if (! line.startsWith("import") || imports.add(line)
(line.startsWith("import") && allowedImports.any { line.contains(it) } }
&& ! disallowedImports.any { line.contains(it) })) { } else {
topLines.add(line) topLines.add(line)
} }
updateCount(line) updateCount(line)
} }
if (foundKeyword && foundClosing && count == 0) { if (foundKeyword && foundClosing && count == 0) {
return BuildScriptInfo(result.toString(), startLine, endLine) sections.add(Section(startLine, endLine))
foundKeyword = false
foundClosing = false
count = 0
startLine = 0
endLine = 0
} }
} }
if (foundKeyword && foundClosing && count == 0) { if (sections.isNotEmpty()) {
return BuildScriptInfo(result.toString(), startLine, endLine) val result = (imports.distinct() + buildScript).joinToString("\n") + "\n"
return BuildScriptInfo(result, sections)
} else { } else {
return null return null
} }

View file

@ -3,7 +3,7 @@ package com.beust.kobalt.misc
import com.beust.kobalt.* import com.beust.kobalt.*
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.IBuildSources
import com.beust.kobalt.maven.Md5 import com.beust.kobalt.maven.Md5
import java.io.* import java.io.*
import java.nio.file.Files import java.nio.file.Files
@ -261,10 +261,9 @@ class KFiles {
/** /**
* The build location for build scripts is .kobalt/build * The build location for build scripts is .kobalt/build
*/ */
fun findBuildScriptLocation(buildFile: BuildFile, jarFile: String) : String { fun findBuildScriptLocation(buildSources: IBuildSources, jarFile: String) : String {
val result = joinDir(buildFile.dotKobaltDir.path, KFiles.SCRIPT_BUILD_DIR, jarFile) val result = joinDir(buildSources.root.path, KFiles.dotKobaltDir.path, KFiles.SCRIPT_BUILD_DIR, jarFile)
kobaltLog(2, "Build file dotKobaltDir: " + buildFile.dotKobaltDir) kobaltLog(2, " Script jar file: $result")
kobaltLog(2, "Script jar file: $result")
return result return result
} }
@ -387,18 +386,7 @@ class KFiles {
} }
} }
fun findBuildFile(projectRoot: String = "."): File { val dotKobaltDir = File(KFiles.joinAndMakeDir(KFiles.KOBALT_DOT_DIR))
val deprecatedLocation = File(Constants.BUILD_FILE_NAME)
val result: File =
if (deprecatedLocation.exists()) {
warn(Constants.BUILD_FILE_NAME + " is in a deprecated location, please move it to "
+ Constants.BUILD_FILE_DIRECTORY)
deprecatedLocation
} else {
File(KFiles.joinDir(projectRoot, Constants.BUILD_FILE_DIRECTORY, Constants.BUILD_FILE_NAME))
}
return result
}
} }
fun findRecursively(directory: File, function: Function1<String, Boolean>): List<String> { fun findRecursively(directory: File, function: Function1<String, Boolean>): List<String> {

View file

@ -3,24 +3,17 @@ package com.beust.kobalt
import com.beust.jcommander.JCommander import com.beust.jcommander.JCommander
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginTask import com.beust.kobalt.app.MainModule
import com.beust.kobalt.app.* import com.beust.kobalt.app.UpdateKobalt
import com.beust.kobalt.app.remote.KobaltClient import com.beust.kobalt.app.remote.KobaltClient
import com.beust.kobalt.app.remote.KobaltServer
import com.beust.kobalt.app.remote.RemoteDependencyData
import com.beust.kobalt.internal.Gc
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.internal.build.BuildFile
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.Http import com.beust.kobalt.maven.Http
import com.beust.kobalt.maven.dependency.FileDependency import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.* import com.beust.kobalt.misc.*
import com.google.common.collect.HashMultimap
import java.io.File import java.io.File
import java.net.URLClassLoader import java.net.URLClassLoader
import java.nio.file.Paths
import javax.inject.Inject import javax.inject.Inject
fun main(argv: Array<String>) { fun main(argv: Array<String>) {
@ -56,21 +49,15 @@ fun mainNoExit(argv: Array<String>): Int {
private class Main @Inject constructor( private class Main @Inject constructor(
val plugins: Plugins, val plugins: Plugins,
val taskManager: TaskManager,
val http: Http, val http: Http,
val files: KFiles, val files: KFiles,
val executors: KobaltExecutors, val executors: KobaltExecutors,
val dependencyManager: DependencyManager, val dependencyManager: DependencyManager,
val checkVersions: CheckVersions,
val github: GithubApi2, val github: GithubApi2,
val updateKobalt: UpdateKobalt, val updateKobalt: UpdateKobalt,
val client: KobaltClient, val client: KobaltClient,
val pluginInfo: PluginInfo, val pluginInfo: PluginInfo,
val projectGenerator: ProjectGenerator, val options: Options) {
val serverFactory: KobaltServer.IFactory,
val projectFinder: ProjectFinder,
val dependencyData: RemoteDependencyData,
val resolveDependency: ResolveDependency) {
data class RunInfo(val jc: JCommander, val args: Args) data class RunInfo(val jc: JCommander, val args: Args)
@ -98,21 +85,20 @@ private class Main @Inject constructor(
// //
// Install plug-ins requested from the command line // Install plug-ins requested from the command line
// //
val pluginClassLoader = installCommandLinePlugins(args) installCommandLinePlugins(args)
if (args.client) { if (args.client) {
client.run() client.run()
return 0 return 0
} }
var result = 0 var result = 1
val latestVersionFuture = github.latestKobaltVersion val latestVersionFuture = github.latestKobaltVersion
try { try {
result = runWithArgs(jc, args, argv, pluginClassLoader) result = runWithArgs(jc, args, argv)
} catch(ex: Throwable) { } catch(ex: Throwable) {
error("", ex.cause ?: ex) error("", ex.cause ?: ex)
result = 1
} }
if (!args.update) { if (!args.update) {
@ -121,126 +107,16 @@ private class Main @Inject constructor(
return result return result
} }
private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>, pluginClassLoader: ClassLoader): Int { private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>): Int {
// val file = File("/Users/beust/.kobalt/repository/com/google/guava/guava/19.0-rc2/guava-19.0-rc2.pom") val p = if (args.buildFile != null) File(args.buildFile) else File(".")
// val md5 = Md5.toMd5(file)
// val md52 = MessageDigest.getInstance("MD5").digest(file.readBytes()).toHexString()
var result = 0
val p = if (args.buildFile != null) File(args.buildFile) else KFiles.findBuildFile()
args.buildFile = p.absolutePath args.buildFile = p.absolutePath
val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
if (!args.update) { if (!args.update) {
println(AsciiArt.banner + Kobalt.version + "\n") println(AsciiArt.banner + Kobalt.version + "\n")
} }
if (args.templates != null) { return options.run(jc, args, argv)
//
// --init: create a new build project and install the wrapper
// Make sure the wrapper won't call us back with --noLaunch
//
projectGenerator.run(args, pluginClassLoader)
// The wrapper has to call System.exit() in order to set the exit code,
// so make sure we call it last (or possibly launch it in a separate JVM).
com.beust.kobalt.wrapper.Main.main(arrayOf("--noLaunch") + argv)
} else if (args.usage) {
jc.usage()
} else {
// Options that don't need Build.kt to be parsed first
if (args.gc) {
Gc().run()
} else if (args.update) {
// --update
updateKobalt.updateKobalt()
} else if (args.serverMode) {
// --server
val port = serverFactory.create(args.force, args.port, { cleanUp() }).call()
} else {
//
// Everything below requires to parse the build file first
//
if (!buildFile.exists()) {
error(buildFile.path.toFile().path + " does not exist")
} else {
val allProjects = projectFinder.initForBuildFile(buildFile, args)
addOptionsFromBuild(args, Kobalt.optionsFromBuild)
if (args.listTemplates) {
// --listTemplates
Templates().displayTemplates(pluginInfo)
} else if (args.projectInfo) {
// --projectInfo
allProjects.forEach {
it.compileDependencies.filter { it.isMaven }.forEach {
resolveDependency.run(it.id)
}
}
} else if (args.dependency != null) {
// --resolve
args.dependency?.let { resolveDependency.run(it) }
} else if (args.tasks) {
// --tasks
displayTasks()
} else if (args.checkVersions) {
// --checkVersions
checkVersions.run(allProjects)
} else if (args.download) {
// --download
updateKobalt.downloadKobalt()
} else {
//
// Launch the build
//
val runTargetResult = taskManager.runTargets(args.targets, allProjects)
if (result == 0) {
result = if (runTargetResult.taskResult.success) 0 else 1
}
// Shutdown all plug-ins
plugins.shutdownPlugins()
// Run the build report contributors
pluginInfo.buildReportContributors.forEach {
it.generateReport(Kobalt.context!!)
}
}
}
}
}
return result
} }
private fun addOptionsFromBuild(args: Args, optionsFromBuild: ArrayList<String>) {
optionsFromBuild.forEach {
when(it) {
Args.SEQUENTIAL -> args.sequential = true
else -> throw IllegalArgumentException("Unsupported option found in kobaltOptions(): " + it)
}
}
}
private fun cleanUp() {
pluginInfo.cleanUp()
taskManager.cleanUp()
}
private fun displayTasks() {
//
// List of tasks, --tasks
//
val tasksByPlugins = HashMultimap.create<String, PluginTask>()
taskManager.annotationTasks.forEach {
tasksByPlugins.put(it.plugin.name, it)
}
val sb = StringBuffer("List of tasks\n")
tasksByPlugins.keySet().forEach { name ->
sb.append("\n " + AsciiArt.horizontalDoubleLine + " $name "
+ AsciiArt.horizontalDoubleLine + "\n")
tasksByPlugins[name].distinctBy(PluginTask::name).sortedBy(PluginTask::name).forEach { task ->
sb.append(" ${task.name}\t\t${task.doc}\n")
}
}
println(sb.toString())
}
} }

View file

@ -1,36 +1,58 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.jcommander.JCommander import com.beust.jcommander.JCommander
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginTask
import com.beust.kobalt.api.Project
import com.beust.kobalt.app.ProjectFinder
import com.beust.kobalt.app.ProjectGenerator import com.beust.kobalt.app.ProjectGenerator
import com.beust.kobalt.app.Templates
import com.beust.kobalt.app.UpdateKobalt import com.beust.kobalt.app.UpdateKobalt
import com.beust.kobalt.app.remote.KobaltServer import com.beust.kobalt.app.remote.KobaltServer
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.CheckVersions
import com.beust.kobalt.wrapper.Main import com.beust.kobalt.wrapper.Main
import com.google.common.collect.HashMultimap
import com.google.inject.Inject import com.google.inject.Inject
import java.io.File import java.io.File
import java.nio.file.Paths
/**
* Some options require a build file, others shouldn't have one and some don't care. This
* class captures these requirements.
*/
open class Option(open val enabled: () -> Boolean, open val action: () -> Unit, open class Option(open val enabled: () -> Boolean, open val action: () -> Unit,
open val requireBuildFile: Boolean = true) open val requireBuildFile: Boolean = true)
class OptionalBuildOption(override val enabled: () -> Boolean, override val action: () -> Unit) class OptionalBuildOption(override val enabled: () -> Boolean, override val action: () -> Unit)
: Option(enabled, action, false) : Option(enabled, action, false)
class Options @Inject constructor( class Options @Inject constructor(
val plugins: Plugins,
val checkVersions: CheckVersions,
val projectGenerator: ProjectGenerator, val projectGenerator: ProjectGenerator,
val pluginInfo: PluginInfo, val pluginInfo: PluginInfo,
val serverFactory: KobaltServer.IFactory, val serverFactory: KobaltServer.IFactory,
val updateKobalt: UpdateKobalt, val updateKobalt: UpdateKobalt,
val taskManager: TaskManager val projectFinder: ProjectFinder,
val taskManager: TaskManager,
val resolveDependency: ResolveDependency
) { ) {
fun run(jc: JCommander, args: Args, argv: Array<String>) { fun run(jc: JCommander, args: Args, argv: Array<String>): Int {
val p = if (args.buildFile != null) File(args.buildFile) else KFiles.findBuildFile() val p = if (args.buildFile != null) File(args.buildFile) else File(".")
val buildFile = BuildFile(Paths.get(p.absolutePath), p.name) // val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
val buildSources = BuildSources(File(p.absolutePath))
var pluginClassLoader = javaClass.classLoader var pluginClassLoader = javaClass.classLoader
val options = arrayListOf<Option>(
val allProjects =
if (buildSources.exists()) projectFinder.initForBuildFile(buildSources, args)
else emptyList<Project>()
// Modify `args` with options found in buildScript { kobaltOptions(...) }, if any
addOptionsFromBuild(args, Kobalt.optionsFromBuild)
val options = listOf<Option>(
OptionalBuildOption( { -> args.templates != null }, { OptionalBuildOption( { -> args.templates != null }, {
// //
// --init: create a new build project and install the wrapper // --init: create a new build project and install the wrapper
@ -48,18 +70,68 @@ class Options @Inject constructor(
OptionalBuildOption( { -> args.serverMode }, { OptionalBuildOption( { -> args.serverMode }, {
// --server // --server
val port = serverFactory.create(args.force, args.port, { cleanUp() }).call() val port = serverFactory.create(args.force, args.port, { cleanUp() }).call()
}),
OptionalBuildOption( { -> args.listTemplates}, {
// --listTemplates
Templates().displayTemplates(pluginInfo)
}),
Option( { -> args.projectInfo }, {
// --projectInfo
allProjects.forEach {
it.compileDependencies.filter { it.isMaven }.forEach {
resolveDependency.run(it.id)
}
}
}),
Option( { args.dependency != null }, {
// --resolve
args.dependency?.let { resolveDependency.run(it) }
}),
Option( { args.tasks }, {
// --tasks
displayTasks()
}),
Option( { args.checkVersions }, {
// --checkVersions
checkVersions.run(allProjects)
}),
Option( { args.download }, {
// --download
updateKobalt.downloadKobalt()
}) })
) )
var processedOption = false
options.forEach { options.forEach {
if (it.enabled()) { if (it.enabled()) {
if ((it.requireBuildFile && buildFile.exists()) || ! it.requireBuildFile) { if ((it.requireBuildFile && buildSources.exists()) || ! it.requireBuildFile) {
it.action() it.action()
} else if (it.requireBuildFile && ! buildFile.exists()) { processedOption = true
throw IllegalArgumentException("Couldn't find a build file") } else if (it.requireBuildFile && ! buildSources.exists()) {
throw KobaltException("Couldn't find a build file")
} }
} }
} }
var result = 0
if (! processedOption) {
//
// Launch the build
//
val runTargetResult = taskManager.runTargets(args.targets, allProjects)
if (result == 0) {
result = if (runTargetResult.taskResult.success) 0 else 1
}
// Shutdown all plug-ins
plugins.shutdownPlugins()
// Run the build report contributors
pluginInfo.buildReportContributors.forEach {
it.generateReport(Kobalt.context!!)
}
}
return result
} }
private fun cleanUp() { private fun cleanUp() {
@ -67,4 +139,32 @@ class Options @Inject constructor(
taskManager.cleanUp() taskManager.cleanUp()
} }
private fun addOptionsFromBuild(args: Args, optionsFromBuild: ArrayList<String>) {
optionsFromBuild.forEach {
when(it) {
Args.SEQUENTIAL -> args.sequential = true
else -> throw IllegalArgumentException("Unsupported option found in kobaltOptions(): " + it)
}
}
}
private fun displayTasks() {
//
// List of tasks, --tasks
//
val tasksByPlugins = HashMultimap.create<String, PluginTask>()
taskManager.annotationTasks.forEach {
tasksByPlugins.put(it.plugin.name, it)
}
val sb = StringBuffer("List of tasks\n")
tasksByPlugins.keySet().forEach { name ->
sb.append("\n " + AsciiArt.horizontalDoubleLine + " $name "
+ AsciiArt.horizontalDoubleLine + "\n")
tasksByPlugins[name].distinctBy(PluginTask::name).sortedBy(PluginTask::name).forEach { task ->
sb.append(" ${task.name}\t\t${task.doc}\n")
}
}
println(sb.toString())
}
} }

View file

@ -1,7 +1,6 @@
package com.beust.kobalt.app package com.beust.kobalt.app
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.Constants
import com.beust.kobalt.Plugins import com.beust.kobalt.Plugins
import com.beust.kobalt.TaskResult import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
@ -12,7 +11,8 @@ import com.beust.kobalt.internal.IncrementalManager
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.ParallelLogger import com.beust.kobalt.internal.ParallelLogger
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.internal.build.IBuildSources
import com.beust.kobalt.internal.build.VersionFile import com.beust.kobalt.internal.build.VersionFile
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.PomGenerator import com.beust.kobalt.maven.PomGenerator
@ -24,7 +24,6 @@ import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import com.google.inject.assistedinject.Assisted import com.google.inject.assistedinject.Assisted
import java.io.File import java.io.File
import java.net.URL import java.net.URL
import java.nio.file.Paths
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -32,7 +31,7 @@ import javax.inject.Inject
* 1) Extract the repos() and plugins() statements in a separate .kt and compile it into preBuildScript.jar. * 1) Extract the repos() and plugins() statements in a separate .kt and compile it into preBuildScript.jar.
* 2) Actually build the whole Build.kt file after adding to the classpath whatever phase 1 found (plugins, repos) * 2) Actually build the whole Build.kt file after adding to the classpath whatever phase 1 found (plugins, repos)
*/ */
class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFiles: List<BuildFile>, class BuildFileCompiler @Inject constructor(@Assisted("buildSources") val buildSources: IBuildSources,
@Assisted val pluginInfo: PluginInfo, val files: KFiles, val plugins: Plugins, @Assisted val pluginInfo: PluginInfo, val files: KFiles, val plugins: Plugins,
val dependencyManager: DependencyManager, val pluginProperties: PluginProperties, val dependencyManager: DependencyManager, val pluginProperties: PluginProperties,
val executors: KobaltExecutors, val buildScriptUtil: BuildScriptUtil, val settings: KobaltSettings, val executors: KobaltExecutors, val buildScriptUtil: BuildScriptUtil, val settings: KobaltSettings,
@ -41,7 +40,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
val parallelLogger: ParallelLogger) { val parallelLogger: ParallelLogger) {
interface IFactory { interface IFactory {
fun create(@Assisted("buildFiles") buildFiles: List<BuildFile>, pluginInfo: PluginInfo) : BuildFileCompiler fun create(@Assisted("buildSources") buildSources: IBuildSources, pluginInfo: PluginInfo) : BuildFileCompiler
} }
private val SCRIPT_JAR = "buildScript.jar" private val SCRIPT_JAR = "buildScript.jar"
@ -85,16 +84,17 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
private fun findProjects(context: KobaltContext): FindProjectResult { private fun findProjects(context: KobaltContext): FindProjectResult {
var errorTaskResult: TaskResult? = null var errorTaskResult: TaskResult? = null
val projects = arrayListOf<Project>() val projects = arrayListOf<Project>()
buildFiles.forEach { buildFile -> run {
val parsedBuildFile = parseBuildFile(context, buildFile) // buildFiles.forEach { buildFile ->
val parsedBuildFile = parseBuildFile(context, buildSources)
parsedBuildFiles.add(parsedBuildFile) parsedBuildFiles.add(parsedBuildFile)
val pluginUrls = parsedBuildFile.pluginUrls val pluginUrls = parsedBuildFile.pluginUrls
val buildScriptJarFile = File(KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR)) val buildScriptJarFile = File(KFiles.findBuildScriptLocation(buildSources, SCRIPT_JAR))
// //
// Save the current build script absolute directory // Save the current build script absolute directory
// //
context.internalContext.absoluteDir = buildFile.absoluteDir context.internalContext.absoluteDir = buildSources.root
// If the script jar files were generated by a different version, wipe them in case the API // If the script jar files were generated by a different version, wipe them in case the API
// changed in-between // changed in-between
@ -108,9 +108,8 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
// Write the modified Build.kt (e.g. maybe profiles were applied) to a temporary file, // Write the modified Build.kt (e.g. maybe profiles were applied) to a temporary file,
// compile it, jar it in buildScript.jar and run it // compile it, jar it in buildScript.jar and run it
val modifiedBuildFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true) val modifiedBuildFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true)
KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode) KFiles.saveFile(modifiedBuildFile, parsedBuildFile.nonBuildScriptCode)
val taskResult = maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path), val taskResult = maybeCompileBuildFile(context, listOf(modifiedBuildFile.path),
"Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath),
buildScriptJarFile, pluginUrls, context.internalContext.forceRecompile, buildScriptJarFile, pluginUrls, context.internalContext.forceRecompile,
parsedBuildFile.containsProfiles) parsedBuildFile.containsProfiles)
if (taskResult.success) { if (taskResult.success) {
@ -130,9 +129,14 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
if (errorTaskResult != null) errorTaskResult!! else TaskResult()) if (errorTaskResult != null) errorTaskResult!! else TaskResult())
} }
private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File, private fun maybeCompileBuildFile(context: KobaltContext, buildSources: BuildSources, buildScriptJarFile: File,
pluginUrls: List<URL>, forceRecompile: Boolean, containsProfiles: Boolean) : TaskResult
= maybeCompileBuildFile(context, buildSources.findSourceFiles().map { it.path }, buildScriptJarFile,
pluginUrls, forceRecompile, containsProfiles)
private fun maybeCompileBuildFile(context: KobaltContext, sourceFiles: List<String>, buildScriptJarFile: File,
pluginUrls: List<URL>, forceRecompile: Boolean, containsProfiles: Boolean) : TaskResult { pluginUrls: List<URL>, forceRecompile: Boolean, containsProfiles: Boolean) : TaskResult {
kobaltLog(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile") kobaltLog(2, "Compiling into $buildScriptJarFile")
// If the user specifed --profiles, always recompile the build file since we don't know if // If the user specifed --profiles, always recompile the build file since we don't know if
// the current buildScript.jar we have contains the correct value for these profiles // the current buildScript.jar we have contains the correct value for these profiles
@ -141,15 +145,15 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
// to have a side file that describes which profiles the current buildScript.jar was // to have a side file that describes which profiles the current buildScript.jar was
// compiled with. // compiled with.
val bs = BuildScriptJarFile(buildScriptJarFile) val bs = BuildScriptJarFile(buildScriptJarFile)
if (! containsProfiles && !forceRecompile && buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) { if (! containsProfiles && !forceRecompile && buildScriptUtil.isUpToDate(buildSources, buildScriptJarFile)) {
kobaltLog(2, " Build file $buildScriptJarFile is up to date") kobaltLog(2, " Build file $buildScriptJarFile is up to date")
return TaskResult() return TaskResult()
} else { } else {
val reason = val reason =
if (containsProfiles) "it contains profiles" if (containsProfiles) "profiles were found"
else if (forceRecompile) "forceRecompile is true" else if (forceRecompile) "forceRecompile is true"
else "it is not up to date" else "it's been modified"
kobaltLog(2, " Need to recompile ${buildFile.name} because $reason") kobaltLog(2, " Need to recompile $buildSources because $reason")
buildScriptJarFile.deleteRecursively() buildScriptJarFile.deleteRecursively()
val buildFileClasspath = Kobalt.buildFileClasspath.map { it.jarFile.get() }.map { it.absolutePath } val buildFileClasspath = Kobalt.buildFileClasspath.map { it.jarFile.get() }.map { it.absolutePath }
@ -157,12 +161,11 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
classpath(files.kobaltJar) classpath(files.kobaltJar)
classpath(pluginUrls.map { it.file }) classpath(pluginUrls.map { it.file })
classpath(buildFileClasspath) classpath(buildFileClasspath)
sourceFiles(listOf(buildFile.path.toFile().absolutePath)) sourceFiles(sourceFiles)
output = buildScriptJarFile output = buildScriptJarFile
noIncrementalKotlin = true noIncrementalKotlin = true
}.compile(context = context) }.compile(context = context)
// //
// Generate the file that contains the list of active profiles for this build file // Generate the file that contains the list of active profiles for this build file
// //
@ -177,6 +180,6 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
* - the source code for the modified Build.kt (after profiles are applied) * - the source code for the modified Build.kt (after profiles are applied)
* - the URL's of all the plug-ins that were found. * - the URL's of all the plug-ins that were found.
*/ */
private fun parseBuildFile(context: KobaltContext, buildFile: BuildFile) = private fun parseBuildFile(context: KobaltContext, buildSources: IBuildSources) =
ParsedBuildFile(buildFile, context, buildScriptUtil, dependencyManager, files) ParsedBuildFile(buildSources, context, buildScriptUtil, dependencyManager, files)
} }

View file

@ -9,7 +9,7 @@ import com.beust.kobalt.api.Project
import com.beust.kobalt.api.annotation.IncrementalTask import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.IBuildSources
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.Topological import com.beust.kobalt.misc.Topological
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.kobaltLog
@ -123,9 +123,9 @@ class BuildScriptUtil @Inject constructor(val plugins: Plugins, val files: KFile
} }
} }
fun isUpToDate(buildFile: BuildFile, jarFile: File) = fun isUpToDate(buildSources: IBuildSources, jarFile: File) =
buildFile.exists() && jarFile.exists() buildSources.exists() && jarFile.exists()
&& buildFile.lastModified < jarFile.lastModified() && buildSources.findSourceFiles().all { it.lastModified() < jarFile.lastModified() }
/** /**
* Make sure all the projects have a unique name. * Make sure all the projects have a unique name.

View file

@ -6,45 +6,49 @@ import com.beust.kobalt.api.Kobalt
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.build.BuildFile import com.beust.kobalt.internal.build.BuildFile
import com.beust.kobalt.internal.build.IBuildSources
import com.beust.kobalt.internal.build.VersionFile import com.beust.kobalt.internal.build.VersionFile
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.BlockExtractor import com.beust.kobalt.misc.*
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import com.beust.kobalt.misc.warn
import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import java.io.File import java.io.File
import java.net.URL import java.net.URL
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.file.Paths
import java.util.regex.Pattern import java.util.regex.Pattern
class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val buildScriptUtil: BuildScriptUtil, class ParsedBuildFile(val buildSources: IBuildSources, val context: KobaltContext, val buildScriptUtil: BuildScriptUtil,
val dependencyManager: DependencyManager, val files: KFiles) { val dependencyManager: DependencyManager, val files: KFiles) {
val pluginList = arrayListOf<String>() private val profileLines = arrayListOf<String>()
val repos = arrayListOf<String>() private val projects = arrayListOf<Project>()
val buildFileClasspath = arrayListOf<String>() private val activeProfiles = arrayListOf<String>()
val profileLines = arrayListOf<String>() private val preBuildScriptJar = KFiles.findBuildScriptLocation(buildSources, "preBuildScript.jar")
val pluginUrls = arrayListOf<URL>() private val preBuildScriptJarFile = File(preBuildScriptJar)
val projects = arrayListOf<Project>() private val nonBuildScript = arrayListOf<String>()
val activeProfiles = arrayListOf<String>()
var containsProfiles = false var containsProfiles = false
val pluginUrls = arrayListOf<URL>()
private val preBuildScript = arrayListOf( /**
"import com.beust.kobalt.*", * Contains the addition of all the build files corrected with the active profiles and with
"import com.beust.kobalt.api.*") * the buildScripts{} sections removed.
val preBuildScriptCode : String get() = preBuildScript.joinToString("\n") */
val nonBuildScriptCode : String get() = nonBuildScript.joinToString("\n")
private val buildScript = arrayListOf<String>()
val buildScriptCode : String get() = buildScript.joinToString("\n")
init { init {
parseBuildFile() // Because profiles may have changed between two builds, we have to delete preBuildScript.jar file
initPluginUrls() // every time and then generate a new one (or skip that phase if no buildScript{} was found in the
// buid files)
preBuildScriptJarFile.delete()
val buildScriptInfo = parseBuildFile()
// Only generate preBuildScript.jar if we found at least one buildScript{}
if (buildScriptInfo != null) {
parseBuildScriptInfo(buildScriptInfo)
}
} }
private fun parseBuildFile() { private fun parseBuildFile() : BuildScriptInfo? {
/** /**
* If the current line matches one of the profiles, turn the declaration into * If the current line matches one of the profiles, turn the declaration into
* val profile = true, otherwise return the same line * val profile = true, otherwise return the same line
@ -61,7 +65,8 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
return Pair(profile == variable, variable) return Pair(profile == variable, variable)
} }
if ((matcher != null && matcher.groups.size > 0) || (oldMatcher != null && oldMatcher.groups.size> 0)) { if ((matcher != null && matcher.groups.isNotEmpty())
|| (oldMatcher != null && oldMatcher.groups.isNotEmpty())) {
containsProfiles = true containsProfiles = true
val match = profileMatch(matcher) val match = profileMatch(matcher)
val oldMatch = profileMatch(oldMatcher) val oldMatch = profileMatch(oldMatcher)
@ -93,61 +98,62 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
return result return result
} }
val buildWithCorrectProfiles = applyProfiles(buildFile.path.toFile().readLines()) //
// Take all the build files and adjust them with the active profiles
//
val buildWithCorrectProfiles = arrayListOf<String>()
buildSources.findSourceFiles().forEach {
buildWithCorrectProfiles.addAll(applyProfiles(it.readLines()))
}
//
// Now extract all the `buildScript{}` blocks from all these build files
//
val buildScriptInfo = BlockExtractor(Pattern.compile("^val.*buildScript.*\\{"), '{', '}') val buildScriptInfo = BlockExtractor(Pattern.compile("^val.*buildScript.*\\{"), '{', '}')
.extractBlock(buildWithCorrectProfiles) .extractBlock(buildWithCorrectProfiles)
if (buildScriptInfo != null) {
kobaltLog(3, "About to compile build file:\n=====\n" + buildScriptInfo.content + "\n=====")
preBuildScript.add(buildScriptInfo.content)
} else {
repos.forEach { preBuildScript.add(it) }
pluginList.forEach { preBuildScript.add(it) }
buildFileClasspath.forEach { preBuildScript.add(it) }
}
// //
// Write the build file excluding the buildScript{} tag since we already ran it // Write the build file to `nonBuildScript` excluding the buildScript{} directives since we already ran them
// //
var lineNumber = 1 var lineNumber = 1
buildFile.path.toFile().forEachLine { line -> buildSources.findSourceFiles().forEach { buildFile ->
if (buildScriptInfo == null || buildFile.forEachLine() { line ->
(lineNumber < buildScriptInfo.startLine || lineNumber > buildScriptInfo.endLine)) { if (buildScriptInfo == null || ! buildScriptInfo.isInSection(lineNumber)) {
buildScript.add(correctProfileLine(line)) val cpl = correctProfileLine(line)
if (cpl.startsWith("import")) nonBuildScript.add(0, cpl)
else nonBuildScript.add(cpl)
}
lineNumber++
} }
lineNumber++
} }
return buildScriptInfo
} }
private fun initPluginUrls() { /**
* Generate preBuildScript.jar based on the buildScript{} found in the build files.
*/
private fun parseBuildScriptInfo(buildScriptInfo: BuildScriptInfo) {
// //
// Compile and run preBuildScriptCode, which contains all the plugins() calls extracted. This // Compile and run preBuildScriptCode, which contains all the plugins() calls extracted. This
// will add all the dynamic plugins found in this code to Plugins.dynamicPlugins // will add all the dynamic plugins found in this code to Plugins.dynamicPlugins
// //
val pluginSourceFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true) val buildScriptSourceFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true)
pluginSourceFile.writeText(preBuildScriptCode, Charset.defaultCharset()) buildScriptSourceFile.writeText(buildScriptInfo.content, Charset.defaultCharset())
kobaltLog(2, "Saved " + KFiles.fixSlashes(pluginSourceFile.absolutePath)) kobaltLog(2, "Saved " + KFiles.fixSlashes(buildScriptSourceFile.absolutePath))
// //
// Compile to preBuildScript.jar // Compile to preBuildScript.jar
// //
val buildScriptJar = KFiles.findBuildScriptLocation(buildFile, "preBuildScript.jar") preBuildScriptJarFile.parentFile.mkdirs()
val buildScriptJarFile = File(buildScriptJar) generateJarFile(context, listOf(buildScriptSourceFile.path), preBuildScriptJarFile)
VersionFile.generateVersionFile(preBuildScriptJarFile.parentFile)
// Because of profiles, it's not possible to find out if a preBuildScript.jar is up to date Kobalt.context!!.internalContext.buildFileOutOfDate = true
// or not so recompile it every time.
// if (! buildScriptUtil.isUpToDate(buildFile, File(buildScriptJar))) {
buildScriptJarFile.parentFile.mkdirs()
generateJarFile(context, BuildFile(Paths.get(pluginSourceFile.path), "Plugins",
Paths.get(buildScriptJar)), buildScriptJarFile, buildFile)
VersionFile.generateVersionFile(buildScriptJarFile.parentFile)
Kobalt.context!!.internalContext.buildFileOutOfDate = true
// }
// //
// Run preBuildScript.jar to initialize plugins and repos // Run preBuildScript.jar to initialize plugins and repos
// //
projects.addAll(buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, arrayListOf<URL>(), context)) projects.addAll(buildScriptUtil.runBuildScriptJarFile(preBuildScriptJarFile, arrayListOf<URL>(), context))
// //
// All the plug-ins are now in Plugins.dynamicPlugins, download them if they're not already // All the plug-ins are now in Plugins.dynamicPlugins, download them if they're not already
@ -157,9 +163,8 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
} }
} }
private fun generateJarFile(context: KobaltContext, buildFile: BuildFile, private fun generateJarFile(context: KobaltContext, sourceFiles: List<String>,
buildScriptJarFile: File, originalFile: BuildFile) { buildScriptJarFile: File, originalFile: BuildFile? = null) {
// //
// Compile the jar file // Compile the jar file
// //
@ -170,14 +175,16 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
val result = kotlinCompilePrivate { val result = kotlinCompilePrivate {
classpath(files.kobaltJar) classpath(files.kobaltJar)
classpath(deps) classpath(deps)
sourceFiles(buildFile.path.toFile().absolutePath) sourceFiles(sourceFiles)
output = outputJar output = outputJar
noIncrementalKotlin = true noIncrementalKotlin = true
}.compile(context = context) }.compile(context = context)
if (! result.success) { if (! result.success) {
throw KobaltException("Couldn't compile ${originalFile.realPath}:\n" val org = originalFile?.realPath ?: sourceFiles.joinToString(",")
+ result.errorMessage) throw KobaltException("Couldn't compile $org:\n" + result.errorMessage)
} }
context.internalContext.noIncrementalKotlin = saved
} }
} }

View file

@ -7,7 +7,7 @@ import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.kobaltLog
import com.google.inject.Inject import com.google.inject.Inject
import java.util.* import java.util.*
@ -15,8 +15,8 @@ import java.util.*
class ProjectFinder @Inject constructor(val buildFileCompilerFactory: BuildFileCompiler.IFactory, class ProjectFinder @Inject constructor(val buildFileCompilerFactory: BuildFileCompiler.IFactory,
val pluginInfo: PluginInfo, val plugins: Plugins) { val pluginInfo: PluginInfo, val plugins: Plugins) {
fun initForBuildFile(buildFile: BuildFile, args: Args): List<Project> { fun initForBuildFile(buildSources: BuildSources, args: Args): List<Project> {
val findProjectResult = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) val findProjectResult = buildFileCompilerFactory.create(buildSources, pluginInfo)
.compileBuildFiles(args) .compileBuildFiles(args)
if (! findProjectResult.taskResult.success) { if (! findProjectResult.taskResult.success) {
throw KobaltException("Couldn't compile build file: " + findProjectResult.taskResult.errorMessage) throw KobaltException("Couldn't compile build file: " + findProjectResult.taskResult.errorMessage)

View file

@ -1,29 +0,0 @@
package com.beust.kobalt.app.remote
import com.beust.kobalt.Args
import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.remote.ICommand
import com.beust.kobalt.internal.remote.ICommandSender
import com.google.gson.Gson
import com.google.gson.JsonObject
import javax.inject.Inject
/**
* This command returns the list of dependencies for the given buildFile.
* Payload:
* { "name" : "getDependencies", "buildFile": "/Users/beust/kotlin/kobalt/kobalt/src/Build.kt" }
* The response is a GetDependenciesData.
*/
@Deprecated(message = "Only used by old server, to be deleted")
class GetDependenciesCommand @Inject constructor(val args: Args, val dependencyData: RemoteDependencyData) : ICommand {
override val name = "getDependencies"
override fun run(sender: ICommandSender, received: JsonObject, initCallback: (String) -> List<Project>) {
val buildFile = received.get("buildFile").asString
val projects = initCallback(buildFile)
val dd = dependencyData.dependenciesDataFor(buildFile, args)
val data = toCommandData(Gson().toJson(dd), dd.errorMessage)
sender.sendData(data)
}
}

View file

@ -3,7 +3,7 @@ package com.beust.kobalt.app.remote
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.app.ProjectFinder import com.beust.kobalt.app.ProjectFinder
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.internal.eventbus.ArtifactDownloadedEvent import com.beust.kobalt.internal.eventbus.ArtifactDownloadedEvent
import com.beust.kobalt.maven.aether.Exceptions import com.beust.kobalt.maven.aether.Exceptions
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
@ -13,6 +13,7 @@ import com.google.gson.Gson
import org.eclipse.jetty.websocket.api.RemoteEndpoint import org.eclipse.jetty.websocket.api.RemoteEndpoint
import org.eclipse.jetty.websocket.api.Session import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.WebSocketListener import org.eclipse.jetty.websocket.api.WebSocketListener
import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
/** /**
@ -43,14 +44,14 @@ class GetDependencyGraphHandler : WebSocketListener {
errorMessage = errorMessage))) errorMessage = errorMessage)))
} }
private fun findBuildFile(map: Map<String, List<String>>) : String? { private fun findBuildFile(map: Map<String, List<String>>) : BuildSources? {
val projectRoot = map[PARAMETER_PROJECT_ROOT] val projectRoot = map[PARAMETER_PROJECT_ROOT]
val buildFile = map[PARAMETER_BUILD_FILE] val buildFile = map[PARAMETER_BUILD_FILE]
val result = val result =
if (projectRoot != null) { if (projectRoot != null) {
KFiles.findBuildFile(projectRoot[0]).absolutePath BuildSources(File(projectRoot[0]))
} else if (buildFile != null) { } else if (buildFile != null) {
buildFile[0] BuildSources(File(buildFile[0]))
} else { } else {
null null
} }
@ -59,13 +60,13 @@ class GetDependencyGraphHandler : WebSocketListener {
override fun onWebSocketConnect(s: Session) { override fun onWebSocketConnect(s: Session) {
session = s session = s
val buildFile = findBuildFile(s.upgradeRequest.parameterMap) val buildSources = findBuildFile(s.upgradeRequest.parameterMap)
fun <T> getInstance(cls: Class<T>) : T = Kobalt.INJECTOR.getInstance(cls) fun <T> getInstance(cls: Class<T>) : T = Kobalt.INJECTOR.getInstance(cls)
// Parse the request // Parse the request
val result = val result =
if (buildFile != null) { if (buildSources != null) {
// Track all the downloads that this dependency call might trigger and // Track all the downloads that this dependency call might trigger and
// send them as a progress message to the web socket // send them as a progress message to the web socket
val eventBus = getInstance(EventBus::class.java) val eventBus = getInstance(EventBus::class.java)
@ -84,10 +85,9 @@ class GetDependencyGraphHandler : WebSocketListener {
val dependencyData = getInstance(RemoteDependencyData::class.java) val dependencyData = getInstance(RemoteDependencyData::class.java)
val args = getInstance(Args::class.java) val args = getInstance(Args::class.java)
val allProjects = projectFinder.initForBuildFile(BuildFile(Paths.get(buildFile), buildFile), val allProjects = projectFinder.initForBuildFile(buildSources, args)
args)
dependencyData.dependenciesDataFor(buildFile, args, object : IProgressListener { dependencyData.dependenciesDataFor(buildSources, args, object : IProgressListener {
override fun onProgress(progress: Int?, message: String?) { override fun onProgress(progress: Int?, message: String?) {
sendWebsocketCommand(s.remote, ProgressCommand.NAME, ProgressCommand(progress, message)) sendWebsocketCommand(s.remote, ProgressCommand.NAME, ProgressCommand(progress, message))
} }

View file

@ -3,8 +3,11 @@ package com.beust.kobalt.app.remote
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.app.MainModule import com.beust.kobalt.app.MainModule
import com.beust.kobalt.homeDir
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.build.BuildSources
import com.google.gson.Gson import com.google.gson.Gson
import java.io.File
//enum class Command(val n: Int, val command: ICommand) { //enum class Command(val n: Int, val command: ICommand) {
// GET_DEPENDENCIES(1, Kobalt.INJECTOR.getInstance(GetDependenciesCommand::class.java)), // GET_DEPENDENCIES(1, Kobalt.INJECTOR.getInstance(GetDependenciesCommand::class.java)),
@ -19,12 +22,13 @@ class KobaltHub(val dependencyData: RemoteDependencyData) {
val args = Args() val args = Args()
fun runCommand(n: Int) : String { fun runCommand(n: Int) : String {
val buildSources = BuildSources(File(homeDir("kotlin/klaxon")))
val data = val data =
when(n) { when(n) {
1 -> Gson().toJson( 1 -> Gson().toJson(
dependencyData.dependenciesDataFor("/Users/beust/kotlin/klaxon/kobalt/src/Build.kt", args)) dependencyData.dependenciesDataFor(buildSources, args))
2 -> Gson().toJson( 2 -> Gson().toJson(
dependencyData.dependenciesDataFor("/Users/beust/kotlin/klaxon/kobalt/src/Build.kt", args, dependencyData.dependenciesDataFor(buildSources, args,
useGraph = true)) useGraph = true))
else -> throw RuntimeException("Unknown command") else -> throw RuntimeException("Unknown command")
} }

View file

@ -70,7 +70,7 @@ class OldServer(val initCallback: (String) -> List<Project>, val cleanUpCallback
} }
} }
private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java) private val COMMAND_CLASSES = listOf(PingCommand::class.java)
private val COMMANDS = COMMAND_CLASSES.map { private val COMMANDS = COMMAND_CLASSES.map {
Kobalt.INJECTOR.getInstance(it).let { Pair(it.name, it) } Kobalt.INJECTOR.getInstance(it).let { Pair(it.name, it) }
}.toMap() }.toMap()

View file

@ -8,7 +8,7 @@ import com.beust.kobalt.internal.DynamicGraph
import com.beust.kobalt.internal.GraphUtil import com.beust.kobalt.internal.GraphUtil
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
@ -16,7 +16,6 @@ import com.beust.kobalt.misc.StringVersion
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.File import java.io.File
import java.nio.file.Paths
interface IProgressListener { interface IProgressListener {
/** /**
@ -29,7 +28,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
val buildFileCompilerFactory: BuildFileCompiler.IFactory, val pluginInfo: PluginInfo, val buildFileCompilerFactory: BuildFileCompiler.IFactory, val pluginInfo: PluginInfo,
val taskManager: TaskManager) { val taskManager: TaskManager) {
fun dependenciesDataFor(buildFilePath: String, args: Args, progressListener: IProgressListener? = null, fun dependenciesDataFor(buildSources: BuildSources, args: Args, progressListener: IProgressListener? = null,
useGraph : Boolean = false): GetDependenciesData { useGraph : Boolean = false): GetDependenciesData {
val projectDatas = arrayListOf<ProjectData>() val projectDatas = arrayListOf<ProjectData>()
@ -41,8 +40,8 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
fun allDeps(l: List<IClasspathDependency>, name: String) = dependencyManager.transitiveClosure(l, fun allDeps(l: List<IClasspathDependency>, name: String) = dependencyManager.transitiveClosure(l,
requiredBy = name) requiredBy = name)
val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand") // val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
val buildFileCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) val buildFileCompiler = buildFileCompilerFactory.create(buildSources, pluginInfo)
val projectResult = buildFileCompiler.compileBuildFiles(args) val projectResult = buildFileCompiler.compileBuildFiles(args)
val pluginDependencies = projectResult.pluginUrls.map { File(it.toURI()) }.map { val pluginDependencies = projectResult.pluginUrls.map { File(it.toURI()) }.map {
@ -125,7 +124,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
.map { toDependencyData2("testCompile", it)} .map { toDependencyData2("testCompile", it)}
} }
val projectRoot = File(buildFilePath).parentFile.parentFile.parentFile val projectRoot = buildSources.file
val allTasks = hashSetOf<TaskData>() val allTasks = hashSetOf<TaskData>()
projectResult.projects.withIndex().forEach { wi -> projectResult.projects.withIndex().forEach { wi ->

View file

@ -1,25 +1,13 @@
package com.beust.kobalt.app.remote package com.beust.kobalt.app.remote
import com.beust.kobalt.Args
import com.beust.kobalt.api.ITemplate import com.beust.kobalt.api.ITemplate
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.app.ProjectFinder
import com.beust.kobalt.app.Templates import com.beust.kobalt.app.Templates
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.build.BuildFile
import com.beust.kobalt.internal.eventbus.ArtifactDownloadedEvent
import com.beust.kobalt.maven.aether.Exceptions
import com.google.common.collect.ListMultimap import com.google.common.collect.ListMultimap
import com.google.common.eventbus.EventBus
import com.google.common.eventbus.Subscribe
import com.google.gson.Gson import com.google.gson.Gson
import org.eclipse.jetty.websocket.api.RemoteEndpoint
import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.WebSocketListener
import spark.ResponseTransformer import spark.ResponseTransformer
import spark.Route import spark.Route
import spark.Spark import spark.Spark
import java.nio.file.Paths
import java.util.concurrent.Executors import java.util.concurrent.Executors
class SparkServer(val cleanUpCallback: () -> Unit, val pluginInfo : PluginInfo) : KobaltServer.IServer { class SparkServer(val cleanUpCallback: () -> Unit, val pluginInfo : PluginInfo) : KobaltServer.IServer {
@ -45,7 +33,6 @@ class SparkServer(val cleanUpCallback: () -> Unit, val pluginInfo : PluginInfo)
override fun run(port: Int) { override fun run(port: Int) {
log.debug("Server running") log.debug("Server running")
Spark.port(port) Spark.port(port)
Spark.webSocket("/v1/getDependencies", GetDependenciesHandler::class.java)
Spark.webSocket("/v1/getDependencyGraph", GetDependencyGraphHandler::class.java) Spark.webSocket("/v1/getDependencyGraph", GetDependencyGraphHandler::class.java)
Spark.get("/ping") { req, res -> Spark.get("/ping") { req, res ->
log.debug(" Received ping") log.debug(" Received ping")
@ -63,30 +50,6 @@ class SparkServer(val cleanUpCallback: () -> Unit, val pluginInfo : PluginInfo)
} }
}) })
//
// The /v0 endpoints are deprecated and will eventually be removed
// (replaced by /v1 which uses WebSockets
jsonRoute("/v0/getDependencies", Route { request, response ->
val buildFile = request.queryParams("buildFile")
val result =
if (buildFile != null) {
try {
val dependencyData = Kobalt.INJECTOR.getInstance(RemoteDependencyData::class.java)
val args = Kobalt.INJECTOR.getInstance(Args::class.java)
dependencyData.dependenciesDataFor(buildFile, args)
} catch(ex: Exception) {
RemoteDependencyData.GetDependenciesData(errorMessage = ex.message)
} finally {
cleanUpCallback()
}
} else {
RemoteDependencyData.GetDependenciesData(
errorMessage = "buildFile wasn't passed in the query parameter")
}
cleanUpCallback()
result
})
jsonRoute("/v0/getTemplates", Route { request, response -> jsonRoute("/v0/getTemplates", Route { request, response ->
TemplatesData.create(Templates().getTemplates(pluginInfo)) TemplatesData.create(Templates().getTemplates(pluginInfo))
}) })
@ -94,93 +57,6 @@ class SparkServer(val cleanUpCallback: () -> Unit, val pluginInfo : PluginInfo)
} }
} }
/**
* Manage the websocket endpoint "/v1/getDependencies".
*/
@Deprecated(message = "Replaced with GetDependencyGraphHandler")
class GetDependenciesHandler : WebSocketListener {
// The SparkJava project refused to merge https://github.com/perwendel/spark/pull/383
// so I have to do dependency injections manually :-(
val projectFinder = Kobalt.INJECTOR.getInstance(ProjectFinder::class.java)
var session: Session? = null
override fun onWebSocketClose(code: Int, reason: String?) {
println("ON CLOSE $code reason: $reason")
}
override fun onWebSocketError(cause: Throwable?) {
Exceptions.printStackTrace(cause!!)
throw UnsupportedOperationException()
}
fun <T> sendWebsocketCommand(endpoint: RemoteEndpoint, commandName: String, payload: T) {
endpoint.sendString(Gson().toJson(WebSocketCommand(commandName, payload = Gson().toJson(payload))))
}
override fun onWebSocketConnect(s: Session) {
session = s
val buildFileParams = s.upgradeRequest.parameterMap["buildFile"]
if (buildFileParams != null) {
val buildFile = buildFileParams[0]
fun <T> getInstance(cls: Class<T>) : T = Kobalt.INJECTOR.getInstance(cls)
val result = if (buildFile != null) {
// Track all the downloads that this dependency call might trigger and
// send them as a progress message to the web socket
val eventBus = getInstance(EventBus::class.java)
val busListener = object {
@Subscribe
fun onArtifactDownloaded(event: ArtifactDownloadedEvent) {
sendWebsocketCommand(s.remote, ProgressCommand.NAME,
ProgressCommand(null, "Downloaded " + event.artifactId))
}
}
eventBus.register(busListener)
// Get the dependencies for the requested build file and send progress to the web
// socket for each project
try {
val dependencyData = getInstance(RemoteDependencyData::class.java)
val args = getInstance(Args::class.java)
val allProjects = projectFinder.initForBuildFile(BuildFile(Paths.get(buildFile), buildFile),
args)
dependencyData.dependenciesDataFor(buildFile, args, object : IProgressListener {
override fun onProgress(progress: Int?, message: String?) {
sendWebsocketCommand(s.remote, ProgressCommand.NAME, ProgressCommand(progress, message))
}
})
} catch(ex: Throwable) {
ex.printStackTrace()
val errorMessage = ex.stackTrace.map { it.toString() }.joinToString("\n<p>")
RemoteDependencyData.GetDependenciesData(errorMessage = errorMessage)
} finally {
SparkServer.cleanUpCallback()
eventBus.unregister(busListener)
}
} else {
RemoteDependencyData.GetDependenciesData(
errorMessage = "buildFile wasn't passed in the query parameter")
}
sendWebsocketCommand(s.remote, RemoteDependencyData.GetDependenciesData.NAME, result)
s.close()
}
}
override fun onWebSocketText(message: String?) {
println("RECEIVED TEXT: $message")
session?.remote?.sendString("Response: $message")
}
override fun onWebSocketBinary(payload: ByteArray?, offset: Int, len: Int) {
println("RECEIVED BINARY: $payload")
}
}
class ProgressCommand(val progress: Int? = null, val message: String? = null) { class ProgressCommand(val progress: Int? = null, val message: String? = null) {
companion object { companion object {
val NAME = "ProgressCommand" val NAME = "ProgressCommand"

View file

@ -1 +1 @@
kobalt.version=1.0.30 kobalt.version=1.0.32

View file

@ -6,7 +6,7 @@ import com.beust.kobalt.app.BuildFileCompiler
import com.beust.kobalt.internal.JvmCompilerPlugin import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.internal.KobaltPluginXml import com.beust.kobalt.internal.KobaltPluginXml
import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.internal.build.SingleFileBuildSources
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 org.testng.annotations.BeforeClass import org.testng.annotations.BeforeClass
@ -70,11 +70,11 @@ open class BaseTest(val compilerFactory: BuildFileCompiler.IFactory? = null) {
val actualBuildFile = createBuildFile(projectDirectory) val actualBuildFile = createBuildFile(projectDirectory)
val tmpBuildFile = createBuildFile(Files.createTempDirectory("").toFile().absolutePath) val tmpBuildFile = createBuildFile(Files.createTempDirectory("").toFile().absolutePath)
val thisBuildFile = BuildFile(Paths.get(tmpBuildFile.absolutePath), "Build.kt", val thisBuildFile = SingleFileBuildSources(tmpBuildFile)
Paths.get(actualBuildFile.absolutePath)) // , "Build.kt",
Kobalt.context?.log(2, "About to compile build file " // Paths.get(actualBuildFile.absolutePath))
+ thisBuildFile.path + " " + thisBuildFile.realPath Kobalt.context?.log(2, "About to compile build file $thisBuildFile"
+ ".kobaltDir: " + thisBuildFile.dotKobaltDir) + ".kobaltDir: " + KFiles.dotKobaltDir)
args.apply { args.apply {
buildFile = actualBuildFile.absolutePath buildFile = actualBuildFile.absolutePath
noIncremental = true noIncremental = true
@ -84,7 +84,7 @@ open class BaseTest(val compilerFactory: BuildFileCompiler.IFactory? = null) {
val pluginInfo = PluginInfo(KobaltPluginXml(), null, null).apply { val pluginInfo = PluginInfo(KobaltPluginXml(), null, null).apply {
projectContributors.add(jvmCompilerPlugin) projectContributors.add(jvmCompilerPlugin)
} }
return compilerFactory!!.create(listOf(thisBuildFile), pluginInfo).compileBuildFiles(args, return compilerFactory!!.create(thisBuildFile, pluginInfo).compileBuildFiles(args,
forceRecompile = true) forceRecompile = true)
} }