From 903f63b268a47cdbe8e497e340bd856996a45011 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 11 Oct 2015 09:19:47 -0700 Subject: [PATCH] Revamping the plug-in class loading. --- src/main/kotlin/com/beust/kobalt/Main.kt | 29 +-- src/main/kotlin/com/beust/kobalt/Plugins.kt | 166 ++++------------ .../com/beust/kobalt/kotlin/ScriptCompiler.kt | 21 ++- .../beust/kobalt/kotlin/ScriptCompiler2.kt | 178 ++++++++++++++++++ .../kotlin/com/beust/kobalt/misc/KFiles.kt | 13 +- .../com/beust/kobalt/misc/KobaltLogger.kt | 4 + .../com/beust/kobalt/misc/MainModule.kt | 2 + .../kobalt/plugin/kotlin/KotlinCompiler.kt | 2 +- 8 files changed, 260 insertions(+), 155 deletions(-) create mode 100644 src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index f6ba6707..c2b0adcc 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -9,6 +9,7 @@ import com.beust.kobalt.kotlin.ScriptCompiler import com.beust.kobalt.maven.* import com.beust.kobalt.misc.* import com.beust.kobalt.SystemProperties +import com.beust.kobalt.kotlin.ScriptCompiler2 import com.beust.kobalt.plugin.publish.JCenterApi import com.beust.kobalt.plugin.publish.UnauthenticatedJCenterApi import com.beust.kobalt.wrapper.Wrapper @@ -35,6 +36,7 @@ public fun main(argv: Array) { private class Main @Inject constructor( val scriptCompilerFactory: ScriptCompiler.IFactory, + val script2: ScriptCompiler2.IFactory, val plugins: Plugins, val taskManager: TaskManager, val http: Http, @@ -115,20 +117,21 @@ private class Main @Inject constructor( if (! buildFile.exists()) { jc.usage() } else { - // Install all the plugins found - plugins.installDynamicPlugins(arrayListOf(buildFile)) - - // Compile the build script - val output = scriptCompilerFactory.create(plugins.pluginJarFiles, - { n: String, j: File? -> - plugins.instantiateClassName(n, j) - }) - .compile(buildFile, buildFile.lastModified(), KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR)) + val allProjects = script2.create(arrayListOf(buildFile)).findProjects() +// // Install all the plugins found +// val classLoaders = plugins.installDynamicPlugins(arrayListOf(buildFile)) +// +// // Compile the build script +// val output = scriptCompilerFactory.create(plugins.pluginJarFiles, +// // @@ +// { cl: ClassLoader, n: String -> plugins.instantiateClassName(classLoaders.get(0), n) } +// ).compile(buildFile, buildFile.lastModified(), +// KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR)) // // Force each project.directory to be an absolute path, if it's not already // - output.projects.forEach { + allProjects.forEach { val fd = File(it.directory) if (! fd.isAbsolute) { it.directory = @@ -140,7 +143,7 @@ private class Main @Inject constructor( } } - plugins.applyPlugins(KobaltContext(args), output.projects) + plugins.applyPlugins(KobaltContext(args), allProjects) if (args.tasks) { // @@ -157,14 +160,14 @@ private class Main @Inject constructor( } println(sb.toString()) } else if (args.checkVersions) { - checkVersions.run(output.projects) + checkVersions.run(allProjects) } else if (args.update) { updateKobalt.updateKobalt() } else { // // Launch the build // - taskManager.runTargets(args.targets, output.projects) + taskManager.runTargets(args.targets, allProjects) } } } diff --git a/src/main/kotlin/com/beust/kobalt/Plugins.kt b/src/main/kotlin/com/beust/kobalt/Plugins.kt index 4f25ee7a..c9a96f18 100644 --- a/src/main/kotlin/com/beust/kobalt/Plugins.kt +++ b/src/main/kotlin/com/beust/kobalt/Plugins.kt @@ -4,8 +4,6 @@ import com.beust.kobalt.api.* import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.TaskResult -import com.beust.kobalt.kotlin.BuildFile -import com.beust.kobalt.kotlin.ScriptCompiler import com.beust.kobalt.maven.DepFactory import com.beust.kobalt.maven.IClasspathDependency import com.beust.kobalt.maven.KobaltException @@ -13,23 +11,17 @@ import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltLogger -import com.beust.kobalt.misc.countChar import com.beust.kobalt.plugin.DefaultPlugin import com.beust.kobalt.plugin.java.JavaPlugin import com.beust.kobalt.plugin.kotlin.KotlinPlugin import com.beust.kobalt.plugin.packaging.PackagingPlugin import com.beust.kobalt.plugin.publish.PublishPlugin import com.google.inject.Provider -import java.io.File import java.io.FileInputStream import java.lang.reflect.Method import java.lang.reflect.Modifier -import java.net.URL import java.net.URLClassLoader -import java.nio.charset.Charset -import java.nio.file.Paths -import java.util.ArrayList -import java.util.HashMap +import java.util.* import java.util.jar.JarInputStream import javax.inject.Inject import javax.inject.Singleton @@ -39,27 +31,25 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider() - private var storageMap = HashMap>() - - fun storeValue(pluginName: String, key: String, value: Any) { - var values = storageMap.get(pluginName) - if (values == null) { - values = hashMapOf() - storageMap.put(pluginName, values) - } - values.put(key, value) - } - - fun getValue(pluginName: String, key: String) : Any? { - return storageMap.get(pluginName)?.get(key) - } +// private var storageMap = HashMap>() +// fun storeValue(pluginName: String, key: String, value: Any) { +// var values = storageMap.get(pluginName) +// if (values == null) { +// values = hashMapOf() +// storageMap.put(pluginName, values) +// } +// values.put(key, value) +// } +// +// fun getValue(pluginName: String, key: String) : Any? { +// return storageMap.get(pluginName)?.get(key) +// } val defaultPlugin : Plugin get() = getPlugin(DefaultPlugin.NAME)!! @@ -112,7 +102,6 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider = plugin.javaClass // Tasks can come from two different places: plugin classes and build files. @@ -180,67 +169,30 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider = arrayListOf() - val dependencies = arrayListOf() - /** - * Parse the build files, locate all the plugins, download them and make them available to be - * used on the classpath of the build file. - */ - fun installDynamicPlugins(files: List) { - // - // Extract all the plugin() and repos() code into a separate script (pluginCode) - // - files.forEach { - val pluginCode = arrayListOf() - var parenCount = 0 - it.path.toFile().forEachLine(Charset.defaultCharset()) { line -> - if (line.startsWith("import")) { - pluginCode.add(line) - } - var index = line.indexOf("plugins(") - if (index == -1) index = line.indexOf("repos(") - if (parenCount > 0 || index >= 0) { - if (index == -1) index = 0 - with(line.substring(index)) { - parenCount += line countChar '(' - if (parenCount > 0) { - pluginCode.add(line) - } - parenCount -= line countChar ')' - } - } - } - - // - // Compile and run pluginCode, which contains all the plugins() calls extracted. This - // will add all the dynamic plugins found in this code to Plugins.dynamicPlugins - // - val pluginSourceFile = KFiles.createTempFile(".kt") - pluginSourceFile.writeText(pluginCode.join("\n"), Charset.defaultCharset()) - log(2, "Saved ${pluginSourceFile.absolutePath}") - scriptCompilerFactory.create(pluginJarFiles, - { n: String, j: File? -> instantiateClassName(n, j) - }).compile(BuildFile(Paths.get(pluginSourceFile.absolutePath), "Plugins"), - it.lastModified(), - KFiles.findBuildScriptLocation(it, "preBuildScript.jar")) + public fun instantiateClassName(classLoader: ClassLoader, className : String) : Class<*> { + try { + log(2, "Instantiating ${className}") + return classLoader.loadClass(className) + } catch(ex: Exception) { + val urls = Arrays.toString((classLoader as URLClassLoader).urLs) + val message = "Couldn't instantiate ${className}\n with classLoader $urls: ${ex}" + println(message) + throw KobaltException(message) } + } - // - // Locate all the jar files for the dynamic plugins we just discovered - // - dependencies.addAll(dynamicPlugins.map { - pluginJarFiles.add(it.jarFile.get().absolutePath) - it - }) + val allTasks : List + get() { + val result = arrayListOf() + Plugins.plugins.forEach { plugin -> + result.addAll(plugin.tasks) + } + return result + } - // - // Materialize all the jar files, instantiate their plugin main class and add it to Plugins - // + fun installPlugins(dependencies: List, classLoader: ClassLoader) { val executor = executors.newExecutor("Plugins", 5) dependencies.forEach { // @@ -256,13 +208,13 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider) log(1, "Added plugin ${c}") @@ -274,48 +226,4 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider { -// fun jarToUrl(jarAbsolutePath: String) = URL("file://" + jarAbsolutePath) - - fun jarToUrl(path: String) = URL("jar", "", "file:${path}!/") - - // We need the jar files to be first in the url list otherwise the Build.kt files resolved - // might be Kobalt's own - val urls = arrayListOf() - buildScriptJarFile?.let { - urls.add(jarToUrl(it.absolutePath)) - } - urls.add(jarToUrl(files.kobaltJar)) - urls.addAll(pluginJarFiles.map { jarToUrl(it) }) - val classLoader = URLClassLoader(urls.toArray(arrayOfNulls(urls.size()))) - - try { - log(2, "Instantiating ${className}") - return classLoader.loadClass(className) - } catch(ex: Exception) { - throw KobaltException("Couldn't instantiate ${className}: ${ex}") - } - } - - val allTasks : List - get() { - val result = arrayListOf() - Plugins.plugins.forEach { plugin -> - result.addAll(plugin.tasks) - } - return result - } - - /** - * @return the tasks accepted by at least one project - */ - fun findTasks(task: String): List { - val tasks = allTasks.filter { task == it.name } - if (tasks.isEmpty()) { - throw KobaltException("Couldn't find task ${task}") - } else { - return tasks - } - } - } \ No newline at end of file diff --git a/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler.kt b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler.kt index bd890601..cd9af012 100644 --- a/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler.kt +++ b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler.kt @@ -8,13 +8,13 @@ import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.maven.KobaltException import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KobaltLogger -import com.beust.kobalt.plugin.kotlin.kotlinCompiler import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate import com.google.inject.assistedinject.Assisted import java.io.File import java.io.FileInputStream import java.io.InputStream import java.lang.reflect.Modifier +import java.net.URLClassLoader import java.util.jar.JarInputStream import javax.inject.Inject import kotlin.properties.Delegates @@ -24,17 +24,17 @@ import kotlin.properties.Delegates */ public class ScriptCompiler @Inject constructor( @Assisted("jarFiles") val jarFiles: List, - @Assisted("instantiate") val instantiate: (String, File?) -> Class<*>, + @Assisted("instantiate") val instantiate: (ClassLoader, String) -> Class<*>, val files: KFiles) : KobaltLogger { interface IFactory { fun create(@Assisted("jarFiles") jarFiles: List, - @Assisted("instantiate") instantiate: (String, File?) -> Class<*>) : ScriptCompiler + @Assisted("instantiate") instantiate: (ClassLoader, String) -> Class<*>) : ScriptCompiler } private var buildScriptJarFile by Delegates.notNull() - public class CompileOutput(val projects: List, val plugins: List) + public class CompileOutput(val projects: List, val plugins: List, val classLoader: ClassLoader) public fun compile(buildFile: BuildFile, lastModified: Long, jarFileName: String) : CompileOutput { @@ -54,7 +54,8 @@ public class ScriptCompiler @Inject constructor( log(2, "Need to recompile ${buildFile.name}") generateJarFile(buildFile) } - return CompileOutput(instantiateBuildFile(), arrayListOf()) + val pi = instantiateBuildFile() + return CompileOutput(pi.projects, arrayListOf(), pi.classLoader) } private fun generateJarFile(buildFile: BuildFile) { @@ -66,10 +67,14 @@ public class ScriptCompiler @Inject constructor( }.compile() } - private fun instantiateBuildFile() : List { + class ProjectInfo(val projects: List, val classLoader: ClassLoader) + + private fun instantiateBuildFile() : ProjectInfo { val result = arrayListOf() var stream : InputStream? = null + val classLoader = URLClassLoader(arrayOf(buildScriptJarFile.toURI().toURL())) try { + log(1, "!!!!!!!!! CREATED CLASSLOADER FOR buildScriptJarFile: $classLoader") stream = JarInputStream(FileInputStream(buildScriptJarFile)) var entry = stream.nextJarEntry @@ -78,7 +83,7 @@ public class ScriptCompiler @Inject constructor( val name = entry.name; if (name.endsWith(".class")) { val className = name.substring(0, name.length() - 6).replace("/", ".") - var cl : Class<*>? = instantiate(className, buildScriptJarFile) + var cl : Class<*>? = instantiate(classLoader, className) if (cl != null) { classes.add(cl) } else { @@ -123,7 +128,7 @@ public class ScriptCompiler @Inject constructor( } // Now that we all the projects, sort them topologically - return Kobalt.sortProjects(result) + return ProjectInfo(Kobalt.sortProjects(result), classLoader) } } diff --git a/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt new file mode 100644 index 00000000..0cb82765 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt @@ -0,0 +1,178 @@ +package com.beust.kobalt.kotlin + +import com.beust.kobalt.Plugins +import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.api.Plugin +import com.beust.kobalt.api.Project +import com.beust.kobalt.api.annotation.Task +import com.beust.kobalt.maven.KobaltException +import com.beust.kobalt.misc.KFiles +import com.beust.kobalt.misc.KobaltLogger +import com.beust.kobalt.misc.countChar +import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate +import com.google.inject.assistedinject.Assisted +import java.io.File +import java.io.FileInputStream +import java.io.InputStream +import java.lang.reflect.Modifier +import java.net.URL +import java.net.URLClassLoader +import java.nio.charset.Charset +import java.nio.file.Paths +import java.util.jar.JarInputStream +import javax.inject.Inject + +public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val buildFiles: List, + val files: KFiles, val plugins: Plugins) : KobaltLogger { + + interface IFactory { + fun create(@Assisted("buildFiles") buildFiles: List) : ScriptCompiler2 + } + + private val SCRIPT_JAR = "buildScript.jar" + + fun findProjects(): List { + val result = arrayListOf() + buildFiles.forEach { buildFile -> + val pluginUrls = findPlugInUrls(buildFile) + val script = File(KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR)) + + log(1, "Compiling main build file ${buildFile.path}") + kotlinCompilePrivate { + classpath(files.kobaltJar) + classpath(pluginUrls.map { it.file }) + sourceFiles(listOf(buildFile.path.toFile().absolutePath)) + output = script.absolutePath + }.compile() + + val output = parseBuildScriptJarFile(script, pluginUrls) + result.addAll(output.projects) + } + return result + } + + private fun findPlugInUrls(buildFile: BuildFile): List { + val result = arrayListOf() + val pluginCode = arrayListOf( + "import com.beust.kobalt.*", + "import com.beust.kobalt.api.*" + ) + var parenCount = 0 + buildFile.path.toFile().forEachLine(Charset.defaultCharset()) { line -> + var index = line.indexOf("plugins(") + if (index == -1) index = line.indexOf("repos(") + if (parenCount > 0 || index >= 0) { + if (index == -1) index = 0 + with(line.substring(index)) { + parenCount += line countChar '(' + if (parenCount > 0) { + pluginCode.add(line) + } + parenCount -= line countChar ')' + } + } + } + + // + // Compile and run pluginCode, which contains all the plugins() calls extracted. This + // will add all the dynamic plugins found in this code to Plugins.dynamicPlugins + // + val pluginSourceFile = KFiles.createTempFile(".kt") + pluginSourceFile.writeText(pluginCode.join("\n"), Charset.defaultCharset()) + log(2, "Saved ${pluginSourceFile.absolutePath}") + + // + // Compile to preBuildScript.jar + // + val buildScriptJar = KFiles.findBuildScriptLocation(buildFile, "preBuildScript.jar") + val buildScriptJarFile = File(buildScriptJar) + buildScriptJarFile.parentFile.mkdirs() + generateJarFile(BuildFile(Paths.get(pluginSourceFile.path), "Plugins"), buildScriptJarFile) + + // + // Run preBuildScript.jar to initialize plugins and repos + // + val projectInfo = parseBuildScriptJarFile(buildScriptJarFile, arrayListOf()) + + // + // All the plug-ins are now in Plugins.dynamicPlugins, download them if they're not already + // + Plugins.dynamicPlugins.forEach { + result.add(it.jarFile.get().toURI().toURL()) + } + + return result + } + + private fun generateJarFile(buildFile: BuildFile, buildScriptJarFile: File) { + kotlinCompilePrivate { + classpath(files.kobaltJar) + sourceFiles(buildFile.path.toFile().absolutePath) + output = buildScriptJarFile.absolutePath + }.compile() + } + + class BuildScriptInfo(val projects: List, val classLoader: ClassLoader) + + private fun parseBuildScriptJarFile(buildScriptJarFile: File, urls: List) : BuildScriptInfo { + val result = arrayListOf() + var stream : InputStream? = null + val allUrls = arrayListOf().plus(urls).plus(arrayOf( + buildScriptJarFile.toURI().toURL(), + File(files.kobaltJar).toURI().toURL())) + .toTypedArray() + val classLoader = URLClassLoader(allUrls) + + // + // Install all the plugins + // + plugins.installPlugins(Plugins.dynamicPlugins, classLoader) + + try { + stream = JarInputStream(FileInputStream(buildScriptJarFile)) + var entry = stream.nextJarEntry + + val classes = hashSetOf>() + while (entry != null) { + val name = entry.name; + if (name.endsWith(".class")) { + val className = name.substring(0, name.length() - 6).replace("/", ".") + var cl : Class<*>? = classLoader.loadClass(className) + if (cl != null) { + classes.add(cl) + } else { + throw KobaltException("Couldn't instantiate ${className}") + } + } + entry = stream.nextJarEntry; + } + + // Invoke all the "val" found on the _DefaultPackage class (the Build.kt file) + classes.filter { cls -> + cls.name != "_DefaultPackage" + }.forEach { cls -> + cls.methods.forEach { method -> + // Invoke vals and see if they return a Project + if (method.name.startsWith("get") && Modifier.isStatic(method.modifiers)) { + val r = method.invoke(null) + if (r is Project) { + log(2, "Found project ${r} in class ${cls}") + result.add(r) + } + } else { + val taskAnnotation = method.getAnnotation(Task::class.java) + if (taskAnnotation != null) { + // Plugins.defaultPlugin.addTask(taskAnnotation, ) + Plugins.defaultPlugin.methodTasks.add(Plugin.MethodTask(method, taskAnnotation)) + } + + }} + } + } finally { + stream?.close() + } + + // Now that we all the projects, sort them topologically + return BuildScriptInfo(Kobalt.sortProjects(result), classLoader) + } +} diff --git a/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt b/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt index 839e4a40..6af6e2c5 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt @@ -18,6 +18,11 @@ public class KFiles { get() { val jar = joinDir(distributionsDir, Kobalt.version, "kobalt/wrapper/kobalt-" + Kobalt.version + ".jar") val jarFile = File(jar) + val envJar = System.getenv("KOBALT_JAR") + if (! jarFile.exists() && envJar != null) { + KobaltLogger.debug("Using kobalt jar $envJar") + return File(envJar).absolutePath + } if (! jarFile.exists()) { // Will only happen when building kobalt itself: the jar file might not be in the dist/ directory // yet since we're currently building it. Instead, use the classes directly @@ -162,10 +167,10 @@ public class KFiles { } public fun createTempFile(suffix : String = "", deleteOnExit: Boolean = false) : File = - File.createTempFile("kobalt", suffix, File(SystemProperties.tmpDir)).let { - if (deleteOnExit) it.deleteOnExit() - return it - } + File.createTempFile("kobalt", suffix, File(SystemProperties.tmpDir)).let { + if (deleteOnExit) it.deleteOnExit() + return it + } fun src(filePath: String): String = KFiles.joinDir(KOBALT_DIR, SRC, filePath) } diff --git a/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt b/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt index 27480154..bc12dd04 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt @@ -20,6 +20,10 @@ public interface KobaltLogger { fun warn(s: String, e: Throwable? = null) { LoggerFactory.getLogger(KobaltLogger::class.java.simpleName).warn(s, e) } + + fun debug(s: String) { + LoggerFactory.getLogger(KobaltLogger::class.java.simpleName).debug(s) + } } final fun log(level: Int = 1, message: String) { diff --git a/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt b/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt index ab2076dd..b90a68be 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt @@ -2,6 +2,7 @@ package com.beust.kobalt.misc import com.beust.kobalt.Args import com.beust.kobalt.kotlin.ScriptCompiler +import com.beust.kobalt.kotlin.ScriptCompiler2 import com.beust.kobalt.maven.ArtifactFetcher import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.maven.Pom @@ -41,6 +42,7 @@ public open class MainModule(val args: Args) : AbstractModule() { JCenterApi.IFactory::class.java, Pom.IFactory::class.java, ScriptCompiler.IFactory::class.java, + ScriptCompiler2.IFactory::class.java, ArtifactFetcher.IFactory::class.java) .forEach { install(builder.build(it)) diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt index a8a9142c..8a8ad72e 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinCompiler.kt @@ -17,7 +17,7 @@ import kotlin.properties.Delegates * @since 08 03, 2015 */ @Singleton -private class KotlinCompiler @Inject constructor(override val localRepo : LocalRepo, +class KotlinCompiler @Inject constructor(override val localRepo : LocalRepo, override val files: com.beust.kobalt.misc.KFiles, override val depFactory: DepFactory, override val dependencyManager: DependencyManager,