1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 08:27: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

View file

@ -3,24 +3,17 @@ package com.beust.kobalt
import com.beust.jcommander.JCommander
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginTask
import com.beust.kobalt.app.*
import com.beust.kobalt.app.MainModule
import com.beust.kobalt.app.UpdateKobalt
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.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.Http
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.*
import com.google.common.collect.HashMultimap
import java.io.File
import java.net.URLClassLoader
import java.nio.file.Paths
import javax.inject.Inject
fun main(argv: Array<String>) {
@ -56,21 +49,15 @@ fun mainNoExit(argv: Array<String>): Int {
private class Main @Inject constructor(
val plugins: Plugins,
val taskManager: TaskManager,
val http: Http,
val files: KFiles,
val executors: KobaltExecutors,
val dependencyManager: DependencyManager,
val checkVersions: CheckVersions,
val github: GithubApi2,
val updateKobalt: UpdateKobalt,
val client: KobaltClient,
val pluginInfo: PluginInfo,
val projectGenerator: ProjectGenerator,
val serverFactory: KobaltServer.IFactory,
val projectFinder: ProjectFinder,
val dependencyData: RemoteDependencyData,
val resolveDependency: ResolveDependency) {
val options: Options) {
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
//
val pluginClassLoader = installCommandLinePlugins(args)
installCommandLinePlugins(args)
if (args.client) {
client.run()
return 0
}
var result = 0
var result = 1
val latestVersionFuture = github.latestKobaltVersion
try {
result = runWithArgs(jc, args, argv, pluginClassLoader)
result = runWithArgs(jc, args, argv)
} catch(ex: Throwable) {
error("", ex.cause ?: ex)
result = 1
}
if (!args.update) {
@ -121,126 +107,16 @@ private class Main @Inject constructor(
return result
}
private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>, pluginClassLoader: ClassLoader): Int {
// val file = File("/Users/beust/.kobalt/repository/com/google/guava/guava/19.0-rc2/guava-19.0-rc2.pom")
// val md5 = Md5.toMd5(file)
// val md52 = MessageDigest.getInstance("MD5").digest(file.readBytes()).toHexString()
var result = 0
val p = if (args.buildFile != null) File(args.buildFile) else KFiles.findBuildFile()
private fun runWithArgs(jc: JCommander, args: Args, argv: Array<String>): Int {
val p = if (args.buildFile != null) File(args.buildFile) else File(".")
args.buildFile = p.absolutePath
val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
if (!args.update) {
println(AsciiArt.banner + Kobalt.version + "\n")
}
if (args.templates != null) {
//
// --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
return options.run(jc, args, argv)
}
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
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.Templates
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.misc.KFiles
import com.beust.kobalt.internal.build.BuildSources
import com.beust.kobalt.misc.CheckVersions
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
* class captures these requirements.
*/
open class Option(open val enabled: () -> Boolean, open val action: () -> Unit,
open val requireBuildFile: Boolean = true)
class OptionalBuildOption(override val enabled: () -> Boolean, override val action: () -> Unit)
: Option(enabled, action, false)
class Options @Inject constructor(
val plugins: Plugins,
val checkVersions: CheckVersions,
val projectGenerator: ProjectGenerator,
val pluginInfo: PluginInfo,
val serverFactory: KobaltServer.IFactory,
val updateKobalt: UpdateKobalt,
val taskManager: TaskManager
val projectFinder: ProjectFinder,
val taskManager: TaskManager,
val resolveDependency: ResolveDependency
) {
fun run(jc: JCommander, args: Args, argv: Array<String>) {
val p = if (args.buildFile != null) File(args.buildFile) else KFiles.findBuildFile()
val buildFile = BuildFile(Paths.get(p.absolutePath), p.name)
fun run(jc: JCommander, args: Args, argv: Array<String>): Int {
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 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 }, {
//
// --init: create a new build project and install the wrapper
@ -48,18 +70,68 @@ class Options @Inject constructor(
OptionalBuildOption( { -> args.serverMode }, {
// --server
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 {
if (it.enabled()) {
if ((it.requireBuildFile && buildFile.exists()) || ! it.requireBuildFile) {
if ((it.requireBuildFile && buildSources.exists()) || ! it.requireBuildFile) {
it.action()
} else if (it.requireBuildFile && ! buildFile.exists()) {
throw IllegalArgumentException("Couldn't find a build file")
processedOption = true
} 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() {
@ -67,4 +139,32 @@ class Options @Inject constructor(
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
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
@ -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,
// 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),
KFiles.saveFile(modifiedBuildFile, parsedBuildFile.nonBuildScriptCode)
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")
else "it's been modified"
kobaltLog(2, " Need to recompile $buildSources because $reason")
buildScriptJarFile.deleteRecursively()
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(pluginUrls.map { it.file })
classpath(buildFileClasspath)
sourceFiles(listOf(buildFile.path.toFile().absolutePath))
sourceFiles(sourceFiles)
output = buildScriptJarFile
noIncrementalKotlin = true
}.compile(context = context)
//
// 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 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,45 +6,49 @@ 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.IBuildSources
import com.beust.kobalt.internal.build.VersionFile
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.BlockExtractor
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.kobaltLog
import com.beust.kobalt.misc.warn
import com.beust.kobalt.misc.*
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>()
val buildFileClasspath = arrayListOf<String>()
val profileLines = arrayListOf<String>()
val pluginUrls = arrayListOf<URL>()
val projects = arrayListOf<Project>()
val activeProfiles = arrayListOf<String>()
private val profileLines = arrayListOf<String>()
private val projects = arrayListOf<Project>()
private val activeProfiles = arrayListOf<String>()
private val preBuildScriptJar = KFiles.findBuildScriptLocation(buildSources, "preBuildScript.jar")
private val preBuildScriptJarFile = File(preBuildScriptJar)
private val nonBuildScript = arrayListOf<String>()
var containsProfiles = false
val pluginUrls = arrayListOf<URL>()
private val preBuildScript = arrayListOf(
"import com.beust.kobalt.*",
"import com.beust.kobalt.api.*")
val preBuildScriptCode : String get() = preBuildScript.joinToString("\n")
private val buildScript = arrayListOf<String>()
val buildScriptCode : String get() = buildScript.joinToString("\n")
/**
* Contains the addition of all the build files corrected with the active profiles and with
* the buildScripts{} sections removed.
*/
val nonBuildScriptCode : String get() = nonBuildScript.joinToString("\n")
init {
parseBuildFile()
initPluginUrls()
// Because profiles may have changed between two builds, we have to delete preBuildScript.jar file
// 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
* 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)
}
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
val match = profileMatch(matcher)
val oldMatch = profileMatch(oldMatcher)
@ -93,61 +98,62 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
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.*\\{"), '{', '}')
.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
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++
}
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
// will add all the dynamic plugins found in this code to Plugins.dynamicPlugins
//
val pluginSourceFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true)
pluginSourceFile.writeText(preBuildScriptCode, Charset.defaultCharset())
kobaltLog(2, "Saved " + KFiles.fixSlashes(pluginSourceFile.absolutePath))
val buildScriptSourceFile = KFiles.createTempBuildFileInTempDirectory(deleteOnExit = true)
buildScriptSourceFile.writeText(buildScriptInfo.content, Charset.defaultCharset())
kobaltLog(2, "Saved " + KFiles.fixSlashes(buildScriptSourceFile.absolutePath))
//
// Compile to preBuildScript.jar
//
val buildScriptJar = KFiles.findBuildScriptLocation(buildFile, "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)
VersionFile.generateVersionFile(buildScriptJarFile.parentFile)
Kobalt.context!!.internalContext.buildFileOutOfDate = true
// }
preBuildScriptJarFile.parentFile.mkdirs()
generateJarFile(context, listOf(buildScriptSourceFile.path), preBuildScriptJarFile)
VersionFile.generateVersionFile(preBuildScriptJarFile.parentFile)
Kobalt.context!!.internalContext.buildFileOutOfDate = true
//
// 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
@ -157,9 +163,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 +175,16 @@ 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)
}
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.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

@ -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.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

@ -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.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)
}