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

Preliminary work for multiple build files.

This commit is contained in:
Cedric Beust 2017-03-27 14:54:51 -07:00
parent 2478040bff
commit ccbfe3bd94
15 changed files with 137 additions and 254 deletions

View file

@ -1,10 +1,8 @@
package com.beust.kobalt.internal.build
import com.beust.kobalt.misc.KFiles
import java.io.File
import java.nio.file.Files
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.
* @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) {
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
/**
* @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

@ -10,7 +10,18 @@ fun main(argv: Array<String>) {
// 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,
@ -26,7 +37,7 @@ class BlockExtractor(val regexp: Pattern, val opening: Char, val closing: Char)
var foundKeyword = false
var foundClosing = false
var count = 0
val result = StringBuffer()
val buildScript = arrayListOf<String>()
val topLines = arrayListOf<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 (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 ->
currentLineNumber++
val found = regexp.matcher(line).matches()
@ -56,26 +71,33 @@ class BlockExtractor(val regexp: Pattern, val opening: Char, val closing: Char)
startLine = currentLineNumber
foundKeyword = true
count = 1
result.append(topLines.joinToString("\n")).append("\n")
result.append(line).append("\n")
buildScript.add(line)
topLines.add(line)
} else {
if (line.startsWith("import")) {
if (allowedImports.any { line.contains(it) } && !disallowedImports.any { line.contains(it) }) {
imports.add(line)
}
} else {
val allowedImports = listOf("com.beust", "java")
val disallowedImports = listOf("com.beust.kobalt.plugin")
if (! line.startsWith("import") ||
(line.startsWith("import") && allowedImports.any { line.contains(it) }
&& ! disallowedImports.any { line.contains(it) })) {
topLines.add(line)
}
updateCount(line)
}
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) {
return BuildScriptInfo(result.toString(), startLine, endLine)
if (sections.isNotEmpty()) {
val result = (imports.distinct() + buildScript).joinToString("\n") + "\n"
return BuildScriptInfo(result, sections)
} else {
return null
}

View file

@ -3,7 +3,7 @@ package com.beust.kobalt.misc
import com.beust.kobalt.*
import com.beust.kobalt.api.Kobalt
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 java.io.*
import java.nio.file.Files
@ -261,9 +261,9 @@ class KFiles {
/**
* The build location for build scripts is .kobalt/build
*/
fun findBuildScriptLocation(buildFile: BuildFile, jarFile: String) : String {
val result = joinDir(buildFile.dotKobaltDir.path, KFiles.SCRIPT_BUILD_DIR, jarFile)
kobaltLog(2, "Build file dotKobaltDir: " + buildFile.dotKobaltDir)
fun findBuildScriptLocation(buildSources: IBuildSources, jarFile: String) : String {
val result = joinDir(buildSources.root.path, KFiles.dotKobaltDir.path, KFiles.SCRIPT_BUILD_DIR, jarFile)
kobaltLog(2, "Build file dotKobaltDir: " + KFiles.dotKobaltDir)
kobaltLog(2, "Script jar file: $result")
return result
}
@ -387,18 +387,7 @@ class KFiles {
}
}
fun findBuildFile(projectRoot: String = "."): File {
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
}
val dotKobaltDir = File(KFiles.joinAndMakeDir(KFiles.KOBALT_DOT_DIR))
}
fun findRecursively(directory: File, function: Function1<String, Boolean>): List<String> {

View file

@ -108,7 +108,7 @@ private class Main @Inject constructor(
}
private fun runWithArgs(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(".")
args.buildFile = p.absolutePath
if (!args.update) {

View file

@ -11,14 +11,12 @@ import com.beust.kobalt.app.UpdateKobalt
import com.beust.kobalt.app.remote.KobaltServer
import com.beust.kobalt.internal.PluginInfo
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.CheckVersions
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.wrapper.Main
import com.google.common.collect.HashMultimap
import com.google.inject.Inject
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
@ -42,12 +40,13 @@ class Options @Inject constructor(
) {
fun run(jc: JCommander, args: Args, argv: Array<String>): Int {
val p = if (args.buildFile != null) File(args.buildFile) else KFiles.findBuildFile()
val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
val p = if (args.buildFile != null) File(args.buildFile) else File(".")
// val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
val buildSources = BuildSources(File(p.absolutePath))
var pluginClassLoader = javaClass.classLoader
val allProjects =
if (buildFile.exists()) projectFinder.initForBuildFile(buildFile, args)
if (buildSources.exists()) projectFinder.initForBuildFile(buildSources, args)
else emptyList<Project>()
// Modify `args` with options found in buildScript { kobaltOptions(...) }, if any
@ -105,10 +104,10 @@ class Options @Inject constructor(
var processedOption = false
options.forEach {
if (it.enabled()) {
if ((it.requireBuildFile && buildFile.exists()) || ! it.requireBuildFile) {
if ((it.requireBuildFile && buildSources.exists()) || ! it.requireBuildFile) {
it.action()
processedOption = true
} else if (it.requireBuildFile && ! buildFile.exists()) {
} else if (it.requireBuildFile && ! buildSources.exists()) {
throw KobaltException("Couldn't find a build file")
}
}

View file

@ -1,7 +1,6 @@
package com.beust.kobalt.app
import com.beust.kobalt.Args
import com.beust.kobalt.Constants
import com.beust.kobalt.Plugins
import com.beust.kobalt.TaskResult
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.ParallelLogger
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.maven.DependencyManager
import com.beust.kobalt.maven.PomGenerator
@ -24,7 +24,6 @@ import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import com.google.inject.assistedinject.Assisted
import java.io.File
import java.net.URL
import java.nio.file.Paths
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.
* 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,
val dependencyManager: DependencyManager, val pluginProperties: PluginProperties,
val executors: KobaltExecutors, val buildScriptUtil: BuildScriptUtil, val settings: KobaltSettings,
@ -41,7 +40,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
val parallelLogger: ParallelLogger) {
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"
@ -85,16 +84,17 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
private fun findProjects(context: KobaltContext): FindProjectResult {
var errorTaskResult: TaskResult? = null
val projects = arrayListOf<Project>()
buildFiles.forEach { buildFile ->
val parsedBuildFile = parseBuildFile(context, buildFile)
run {
// buildFiles.forEach { buildFile ->
val parsedBuildFile = parseBuildFile(context, buildSources)
parsedBuildFiles.add(parsedBuildFile)
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
//
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
// changed in-between
@ -109,8 +109,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
// compile it, jar it in buildScript.jar and run it
val modifiedBuildFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true)
KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode)
val taskResult = maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path),
"Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath),
val taskResult = maybeCompileBuildFile(context, listOf(modifiedBuildFile.path),
buildScriptJarFile, pluginUrls, context.internalContext.forceRecompile,
parsedBuildFile.containsProfiles)
if (taskResult.success) {
@ -130,9 +129,14 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
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 {
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
// 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
// compiled with.
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")
return TaskResult()
} else {
val reason =
if (containsProfiles) "it contains profiles"
if (containsProfiles) "profiles were found"
else if (forceRecompile) "forceRecompile is true"
else "it is not up to date"
kobaltLog(2, " Need to recompile ${buildFile.name} because $reason")
kobaltLog(2, " Need to recompile $buildSources because $reason")
buildScriptJarFile.deleteRecursively()
val buildFileClasspath = Kobalt.buildFileClasspath.map { it.jarFile.get() }.map { it.absolutePath }
@ -157,7 +161,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
classpath(files.kobaltJar)
classpath(pluginUrls.map { it.file })
classpath(buildFileClasspath)
sourceFiles(listOf(buildFile.path.toFile().absolutePath))
sourceFiles(sourceFiles)
output = buildScriptJarFile
noIncrementalKotlin = true
}.compile(context = context)
@ -177,6 +181,6 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
* - the source code for the modified Build.kt (after profiles are applied)
* - the URL's of all the plug-ins that were found.
*/
private fun parseBuildFile(context: KobaltContext, buildFile: BuildFile) =
ParsedBuildFile(buildFile, context, buildScriptUtil, dependencyManager, files)
private fun parseBuildFile(context: KobaltContext, buildSources: IBuildSources) =
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.Task
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.Topological
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) =
buildFile.exists() && jarFile.exists()
&& buildFile.lastModified < jarFile.lastModified()
fun isUpToDate(buildSources: IBuildSources, jarFile: File) =
buildSources.exists() && jarFile.exists()
&& buildSources.findSourceFiles().all { it.lastModified() < jarFile.lastModified() }
/**
* Make sure all the projects have a unique name.

View file

@ -6,6 +6,8 @@ import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.Project
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.maven.DependencyManager
import com.beust.kobalt.misc.BlockExtractor
@ -16,10 +18,9 @@ import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import java.io.File
import java.net.URL
import java.nio.charset.Charset
import java.nio.file.Paths
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 pluginList = arrayListOf<String>()
val repos = arrayListOf<String>()
@ -36,8 +37,8 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
"import com.beust.kobalt.api.*")
val preBuildScriptCode : String get() = preBuildScript.joinToString("\n")
private val buildScript = arrayListOf<String>()
val buildScriptCode : String get() = buildScript.joinToString("\n")
private val nonBuildScript = arrayListOf<String>()
val buildScriptCode : String get() = nonBuildScript.joinToString("\n")
init {
parseBuildFile()
@ -93,12 +94,16 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
return result
}
val buildWithCorrectProfiles = applyProfiles(buildFile.path.toFile().readLines())
val buildWithCorrectProfiles = arrayListOf<String>()
buildSources.findSourceFiles().forEach {
buildWithCorrectProfiles.addAll(applyProfiles(it.readLines()))
}
val buildScriptInfo = BlockExtractor(Pattern.compile("^val.*buildScript.*\\{"), '{', '}')
.extractBlock(buildWithCorrectProfiles)
if (buildScriptInfo != null) {
kobaltLog(3, "About to compile build file:\n=====\n" + buildScriptInfo.content + "\n=====")
kobaltLog(2, "About to compile build file:\n=====\n" + buildScriptInfo.content + "\n=====")
preBuildScript.add(buildScriptInfo.content)
} else {
repos.forEach { preBuildScript.add(it) }
@ -107,17 +112,20 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
}
//
// Write the build file excluding the buildScript{} tag since we already ran it
// Write the build file excluding the nonBuildScript{} tag since we already ran it
//
var lineNumber = 1
buildFile.path.toFile().forEachLine { line ->
if (buildScriptInfo == null ||
(lineNumber < buildScriptInfo.startLine || lineNumber > buildScriptInfo.endLine)) {
buildScript.add(correctProfileLine(line))
buildSources.findSourceFiles().forEach { buildFile ->
buildFile.forEachLine() { line ->
if (buildScriptInfo == null || ! buildScriptInfo.isInSection(lineNumber)) {
val cpl = correctProfileLine(line)
if (cpl.startsWith("import")) nonBuildScript.add(0, cpl)
else nonBuildScript.add(cpl)
}
lineNumber++
}
}
}
private fun initPluginUrls() {
//
@ -131,15 +139,14 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
//
// Compile to preBuildScript.jar
//
val buildScriptJar = KFiles.findBuildScriptLocation(buildFile, "preBuildScript.jar")
val buildScriptJar = KFiles.findBuildScriptLocation(buildSources, "preBuildScript.jar")
val buildScriptJarFile = File(buildScriptJar)
// Because of profiles, it's not possible to find out if a preBuildScript.jar is up to date
// 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)
generateJarFile(context, listOf(pluginSourceFile.path), buildScriptJarFile)
VersionFile.generateVersionFile(buildScriptJarFile.parentFile)
Kobalt.context!!.internalContext.buildFileOutOfDate = true
// }
@ -157,9 +164,8 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
}
}
private fun generateJarFile(context: KobaltContext, buildFile: BuildFile,
buildScriptJarFile: File, originalFile: BuildFile) {
private fun generateJarFile(context: KobaltContext, sourceFiles: List<String>,
buildScriptJarFile: File, originalFile: BuildFile? = null) {
//
// Compile the jar file
//
@ -170,14 +176,18 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
val result = kotlinCompilePrivate {
classpath(files.kobaltJar)
classpath(deps)
sourceFiles(buildFile.path.toFile().absolutePath)
sourceFiles(sourceFiles)
output = outputJar
noIncrementalKotlin = true
}.compile(context = context)
if (! result.success) {
throw KobaltException("Couldn't compile ${originalFile.realPath}:\n"
+ result.errorMessage)
}
val org = originalFile?.realPath ?: sourceFiles.joinToString(",")
throw KobaltException("Couldn't compile $org:\n" + result.errorMessage)
}
}
private fun generateJarFile(context: KobaltContext, buildSources: BuildSources,
buildScriptJarFile: File)
= generateJarFile(context, buildSources.findSourceFiles().map { it.path }, buildScriptJarFile)
}

View file

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

View file

@ -3,7 +3,7 @@ package com.beust.kobalt.app.remote
import com.beust.kobalt.Args
import com.beust.kobalt.api.Kobalt
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.maven.aether.Exceptions
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.Session
import org.eclipse.jetty.websocket.api.WebSocketListener
import java.io.File
import java.nio.file.Paths
/**
@ -43,14 +44,14 @@ class GetDependencyGraphHandler : WebSocketListener {
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 buildFile = map[PARAMETER_BUILD_FILE]
val result =
if (projectRoot != null) {
KFiles.findBuildFile(projectRoot[0]).absolutePath
BuildSources(File(projectRoot[0]))
} else if (buildFile != null) {
buildFile[0]
BuildSources(File(buildFile[0]))
} else {
null
}
@ -59,13 +60,13 @@ class GetDependencyGraphHandler : WebSocketListener {
override fun onWebSocketConnect(s: Session) {
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)
// Parse the request
val result =
if (buildFile != null) {
if (buildSources != 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)
@ -84,10 +85,9 @@ class GetDependencyGraphHandler : WebSocketListener {
val dependencyData = getInstance(RemoteDependencyData::class.java)
val args = getInstance(Args::class.java)
val allProjects = projectFinder.initForBuildFile(BuildFile(Paths.get(buildFile), buildFile),
args)
val allProjects = projectFinder.initForBuildFile(buildSources, args)
dependencyData.dependenciesDataFor(buildFile, args, object : IProgressListener {
dependencyData.dependenciesDataFor(buildSources, args, object : IProgressListener {
override fun onProgress(progress: Int?, message: String?) {
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.api.Kobalt
import com.beust.kobalt.app.MainModule
import com.beust.kobalt.homeDir
import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.build.BuildSources
import com.google.gson.Gson
import java.io.File
//enum class Command(val n: Int, val command: ICommand) {
// GET_DEPENDENCIES(1, Kobalt.INJECTOR.getInstance(GetDependenciesCommand::class.java)),
@ -19,12 +22,13 @@ class KobaltHub(val dependencyData: RemoteDependencyData) {
val args = Args()
fun runCommand(n: Int) : String {
val buildSources = BuildSources(File(homeDir("kotlin/klaxon")))
val data =
when(n) {
1 -> Gson().toJson(
dependencyData.dependenciesDataFor("/Users/beust/kotlin/klaxon/kobalt/src/Build.kt", args))
dependencyData.dependenciesDataFor(buildSources, args))
2 -> Gson().toJson(
dependencyData.dependenciesDataFor("/Users/beust/kotlin/klaxon/kobalt/src/Build.kt", args,
dependencyData.dependenciesDataFor(buildSources, args,
useGraph = true))
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 {
Kobalt.INJECTOR.getInstance(it).let { Pair(it.name, it) }
}.toMap()

View file

@ -8,7 +8,7 @@ import com.beust.kobalt.internal.DynamicGraph
import com.beust.kobalt.internal.GraphUtil
import com.beust.kobalt.internal.PluginInfo
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.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors
@ -16,7 +16,6 @@ import com.beust.kobalt.misc.StringVersion
import com.beust.kobalt.misc.log
import com.google.inject.Inject
import java.io.File
import java.nio.file.Paths
interface IProgressListener {
/**
@ -29,7 +28,7 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v
val buildFileCompilerFactory: BuildFileCompiler.IFactory, val pluginInfo: PluginInfo,
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 {
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,
requiredBy = name)
val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
val buildFileCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
// val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
val buildFileCompiler = buildFileCompilerFactory.create(buildSources, pluginInfo)
val projectResult = buildFileCompiler.compileBuildFiles(args)
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)}
}
val projectRoot = File(buildFilePath).parentFile.parentFile.parentFile
val projectRoot = buildSources.file
val allTasks = hashSetOf<TaskData>()
projectResult.projects.withIndex().forEach { wi ->

View file

@ -1,25 +1,13 @@
package com.beust.kobalt.app.remote
import com.beust.kobalt.Args
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.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.eventbus.EventBus
import com.google.common.eventbus.Subscribe
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.Route
import spark.Spark
import java.nio.file.Paths
import java.util.concurrent.Executors
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) {
log.debug("Server running")
Spark.port(port)
Spark.webSocket("/v1/getDependencies", GetDependenciesHandler::class.java)
Spark.webSocket("/v1/getDependencyGraph", GetDependencyGraphHandler::class.java)
Spark.get("/ping") { req, res ->
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 ->
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) {
companion object {
val NAME = "ProgressCommand"

View file

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