diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/build/BuildFile.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/build/BuildFile.kt index b860f446..a2eb91e9 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/build/BuildFile.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/internal/build/BuildFile.kt @@ -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() - } } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/BlockExtractor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/BlockExtractor.kt index c2bdc557..4e92ea2a 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/BlockExtractor.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/BlockExtractor.kt @@ -10,7 +10,18 @@ fun main(argv: Array) { // 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
) { + 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() val topLines = arrayListOf() 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() + val sections = arrayListOf
() 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 { - 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) })) { + if (line.startsWith("import")) { + if (allowedImports.any { line.contains(it) } && !disallowedImports.any { line.contains(it) }) { + imports.add(line) + } + } else { 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 } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt index e1e9a709..d78e8cff 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt @@ -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): List { diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index 34e7f467..75f27bda 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -108,7 +108,7 @@ private class Main @Inject constructor( } private fun runWithArgs(jc: JCommander, args: Args, argv: Array): 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) { diff --git a/src/main/kotlin/com/beust/kobalt/Options.kt b/src/main/kotlin/com/beust/kobalt/Options.kt index 4c7f6f95..9b29a831 100644 --- a/src/main/kotlin/com/beust/kobalt/Options.kt +++ b/src/main/kotlin/com/beust/kobalt/Options.kt @@ -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): 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() // 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") } } diff --git a/src/main/kotlin/com/beust/kobalt/app/BuildFileCompiler.kt b/src/main/kotlin/com/beust/kobalt/app/BuildFileCompiler.kt index 68cabd40..fa98ca10 100644 --- a/src/main/kotlin/com/beust/kobalt/app/BuildFileCompiler.kt +++ b/src/main/kotlin/com/beust/kobalt/app/BuildFileCompiler.kt @@ -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, +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, 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() - 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, forceRecompile: Boolean, containsProfiles: Boolean) : TaskResult + = maybeCompileBuildFile(context, buildSources.findSourceFiles().map { it.path }, buildScriptJarFile, + pluginUrls, forceRecompile, containsProfiles) + + private fun maybeCompileBuildFile(context: KobaltContext, sourceFiles: List, buildScriptJarFile: File, pluginUrls: List, 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) } diff --git a/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt b/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt index 55f980f8..a3af4a93 100644 --- a/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt +++ b/src/main/kotlin/com/beust/kobalt/app/BuildScriptUtil.kt @@ -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. diff --git a/src/main/kotlin/com/beust/kobalt/app/ParsedBuildFile.kt b/src/main/kotlin/com/beust/kobalt/app/ParsedBuildFile.kt index de6fa8fc..c6d82e05 100644 --- a/src/main/kotlin/com/beust/kobalt/app/ParsedBuildFile.kt +++ b/src/main/kotlin/com/beust/kobalt/app/ParsedBuildFile.kt @@ -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() val repos = arrayListOf() @@ -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() - val buildScriptCode : String get() = buildScript.joinToString("\n") + private val nonBuildScript = arrayListOf() + 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() + 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,15 +112,18 @@ 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++ } - lineNumber++ } } @@ -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, + 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) } diff --git a/src/main/kotlin/com/beust/kobalt/app/ProjectFinder.kt b/src/main/kotlin/com/beust/kobalt/app/ProjectFinder.kt index 4a182678..109d72d7 100644 --- a/src/main/kotlin/com/beust/kobalt/app/ProjectFinder.kt +++ b/src/main/kotlin/com/beust/kobalt/app/ProjectFinder.kt @@ -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 { - val findProjectResult = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) + fun initForBuildFile(buildSources: BuildSources, args: Args): List { + val findProjectResult = buildFileCompilerFactory.create(buildSources, pluginInfo) .compileBuildFiles(args) if (! findProjectResult.taskResult.success) { throw KobaltException("Couldn't compile build file: " + findProjectResult.taskResult.errorMessage) diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/GetDependencyGraphHandler.kt b/src/main/kotlin/com/beust/kobalt/app/remote/GetDependencyGraphHandler.kt index 8c795154..a17f5dc3 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/GetDependencyGraphHandler.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/GetDependencyGraphHandler.kt @@ -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? { + private fun findBuildFile(map: Map>) : 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 getInstance(cls: Class) : 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)) } diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltHub.kt b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltHub.kt index 159b07e3..75982f7d 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltHub.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltHub.kt @@ -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") } diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt index d95c9964..6636f2be 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt @@ -70,7 +70,7 @@ class OldServer(val initCallback: (String) -> List, 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() diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/RemoteDependencyData.kt b/src/main/kotlin/com/beust/kobalt/app/remote/RemoteDependencyData.kt index 5d2011f0..ab1c1175 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/RemoteDependencyData.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/RemoteDependencyData.kt @@ -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() @@ -41,8 +40,8 @@ class RemoteDependencyData @Inject constructor(val executors: KobaltExecutors, v fun allDeps(l: List, 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() projectResult.projects.withIndex().forEach { wi -> diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt index 5aaf90fb..49f3e4a1 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/SparkServer.kt @@ -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 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 getInstance(cls: Class) : 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

") - 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" diff --git a/src/test/kotlin/com/beust/kobalt/BaseTest.kt b/src/test/kotlin/com/beust/kobalt/BaseTest.kt index 97a08242..0ec243ab 100644 --- a/src/test/kotlin/com/beust/kobalt/BaseTest.kt +++ b/src/test/kotlin/com/beust/kobalt/BaseTest.kt @@ -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) }