From 91b9cc64f41517bd1af5c7544a0e10a3854d19ed Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 5 Nov 2015 02:52:08 -0800 Subject: [PATCH] Switch to the new plug-in architecture. --- src/main/kotlin/com/beust/kobalt/Main.kt | 29 +++-- src/main/kotlin/com/beust/kobalt/Plugins.kt | 3 + .../com/beust/kobalt/api/KobaltPluginFile.kt | 104 --------------- .../com/beust/kobalt/api/KobaltPluginXml.kt | 123 ++++++++++++++++++ .../internal/remote/GetDependenciesCommand.kt | 5 +- .../com/beust/kobalt/misc/MainModule.kt | 7 +- 6 files changed, 148 insertions(+), 123 deletions(-) delete mode 100644 src/main/kotlin/com/beust/kobalt/api/KobaltPluginFile.kt create mode 100644 src/main/kotlin/com/beust/kobalt/api/KobaltPluginXml.kt diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index 0024b0ce..28ffa574 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -1,7 +1,9 @@ package com.beust.kobalt import com.beust.jcommander.JCommander -import com.beust.kobalt.api.* +import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.api.PluginInfo +import com.beust.kobalt.api.Project import com.beust.kobalt.internal.TaskManager import com.beust.kobalt.internal.remote.KobaltClient import com.beust.kobalt.internal.remote.KobaltServer @@ -17,7 +19,6 @@ import java.io.File import java.nio.file.Paths import java.util.* import javax.inject.Inject -import javax.xml.bind.JAXBContext public fun main(argv: Array) { val result = mainNoExit(argv) @@ -34,6 +35,7 @@ private fun parseArgs(argv: Array): Main.RunInfo { return Main.RunInfo(result, args) } + public fun mainNoExit(argv: Array) : Int { val (jc, args) = parseArgs(argv) Kobalt.INJECTOR = Guice.createInjector(MainModule(args)) @@ -54,7 +56,7 @@ private class Main @Inject constructor( val updateKobalt: UpdateKobalt, val client: KobaltClient, val server: KobaltServer, - val pluginInfoDescription: PluginInfoDescription) { + val pluginInfo: PluginInfo) { data class RunInfo(val jc: JCommander, val args: Args) @@ -93,11 +95,11 @@ private class Main @Inject constructor( public fun runTest() { val file = File("src\\main\\resources\\META-INF\\plugin.xml") - val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java) - - val kotlinPlugin : KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(file) as KobaltPluginXml - val pluginInfo = PluginInfo.create(kotlinPlugin) - System.out.println(kotlinPlugin.name) +// val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java) +// +// val kotlinPlugin : KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(file) as KobaltPluginXml +// val pluginInfo = PluginInfo.create(kotlinPlugin) +// System.out.println(kotlinPlugin.name) } private fun runWithArgs(jc: JCommander, args: Args) : Int { @@ -124,10 +126,10 @@ private class Main @Inject constructor( if (! buildFile.exists()) { error(buildFile.path.toFile().path + " does not exist") } else { - var allProjects = listOf() - val pluginInfo = PluginInfo(pluginInfoDescription) + var allProjects = arrayListOf() try { - allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo).compileBuildFiles(args) + allProjects.addAll(buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) + .compileBuildFiles(args)) } catch(ex: Throwable) { // This can happen if the ABI for the build script file changed. Try to wipe .kobalt. log(2, "Couldn't parse preBuildScript.jar: ${ex.message}") @@ -136,8 +138,8 @@ private class Main @Inject constructor( return 1 } else { log(1, "Deleted .kobalt") - allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) - .compileBuildFiles(args) + allProjects.addAll(buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) + .compileBuildFiles(args)) } } @@ -172,7 +174,6 @@ private class Main @Inject constructor( } return result } - private fun findBuildFile(): File { val files = arrayListOf("Build.kt", "build.kobalt", KFiles.src("build.kobalt"), KFiles.src("Build.kt")) diff --git a/src/main/kotlin/com/beust/kobalt/Plugins.kt b/src/main/kotlin/com/beust/kobalt/Plugins.kt index d2bab348..130055a7 100644 --- a/src/main/kotlin/com/beust/kobalt/Plugins.kt +++ b/src/main/kotlin/com/beust/kobalt/Plugins.kt @@ -37,6 +37,9 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider() // private var storageMap = HashMap>() // fun storeValue(pluginName: String, key: String, value: Any) { diff --git a/src/main/kotlin/com/beust/kobalt/api/KobaltPluginFile.kt b/src/main/kotlin/com/beust/kobalt/api/KobaltPluginFile.kt deleted file mode 100644 index 236a6836..00000000 --- a/src/main/kotlin/com/beust/kobalt/api/KobaltPluginFile.kt +++ /dev/null @@ -1,104 +0,0 @@ -package com.beust.kobalt.api - -import com.beust.kobalt.maven.IClasspathDependency -import com.beust.kobalt.plugin.java.JavaPlugin -import com.beust.kobalt.plugin.kotlin.KotlinPlugin -import java.util.* -import javax.xml.bind.annotation.XmlElement -import javax.xml.bind.annotation.XmlRootElement - -class ProjectDescription(val project: Project, val dependsOn: List) - -interface IProjectContributor { - fun projects() : List -} - -/** - * Implement this interface in order to add your own entries to the classpath. A list of contributors - * can be found on the `KobaltContext`. - */ -interface IClasspathContributor { - fun entriesFor(project: Project) : Collection -} - -interface IFactory { - fun instanceOf(c: Class) : T -} - -class ContributorFactory : IFactory { - override fun instanceOf(c: Class) : T = Kobalt.INJECTOR.getInstance(c) -} - -/** - * All the information gathered from the various plugin.xml that were collected. - */ -class PluginInfoDescription { - fun instanceOf(c: Class) : T = Kobalt.INJECTOR.getInstance(c) - - val projectContributors : ArrayList> = - arrayListOf(JavaPlugin::class.java, KotlinPlugin::class.java) - - val classpathContributors: ArrayList> = - arrayListOf(KotlinPlugin::class.java) - - // Future contributors: - // compilerArgs - // source files - // compilers - // --init -} - -/** - * Turn the classes found in PluginInfoDescription into concrete objects that plugins can then use. - */ -class PluginInfo(val description: PluginInfoDescription?) { - val projectContributors = arrayListOf() - val classpathContributors = arrayListOf() - - companion object { - fun create(xml: KobaltPluginXml) : PluginInfo { - val factory = Class.forName(xml.factoryClassName).newInstance() as IFactory - val result = PluginInfo(null) - xml.classpathContributors?.className?.forEach { - result.classpathContributors.add(factory.instanceOf(Class.forName(it)) as IClasspathContributor) - } - xml.projectContributors?.className?.forEach { - result.projectContributors.add(factory.instanceOf(Class.forName(it)) as IProjectContributor) - } - return result - } - } - - init { - if (description != null) { - classpathContributors.addAll(description.classpathContributors.map { description.instanceOf(it) }) - projectContributors.addAll(description.projectContributors.map { description.instanceOf(it) }) - } - } -} - -class ContributorXml { - @XmlElement @JvmField - val name: String? = null -} - -class ContributorsXml { - @XmlElement(name = "class-name") @JvmField - var className: List = arrayListOf() -} - -@XmlRootElement(name = "kobalt-plugin") -class KobaltPluginXml { - @XmlElement @JvmField - var name: String? = null - - @XmlElement(name = "factory-class-name") @JvmField - var factoryClassName: String? = null - - @XmlElement(name = "classpath-contributors") @JvmField - var classpathContributors : ContributorsXml? = null - - @XmlElement(name = "project-contributors") @JvmField - var projectContributors : ContributorsXml? = null -} - diff --git a/src/main/kotlin/com/beust/kobalt/api/KobaltPluginXml.kt b/src/main/kotlin/com/beust/kobalt/api/KobaltPluginXml.kt new file mode 100644 index 00000000..266a3f10 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/api/KobaltPluginXml.kt @@ -0,0 +1,123 @@ +package com.beust.kobalt.api + +import com.beust.kobalt.maven.IClasspathDependency +import com.beust.kobalt.misc.KFiles +import java.io.InputStream +import javax.xml.bind.JAXBContext +import javax.xml.bind.annotation.XmlElement +import javax.xml.bind.annotation.XmlRootElement + +///// +// Contributors +// + +class ProjectDescription(val project: Project, val dependsOn: List) + +/** + * Implement this interface in order to add your own projects. + */ +interface IProjectContributor { + fun projects() : List +} + +/** + * Implement this interface to add your own entries to the classpath. + */ +interface IClasspathContributor { + fun entriesFor(project: Project) : Collection +} + +/** + * The factory function to use to instantiate all the contributors and other entities + * found in plugin.xml. + */ +interface IFactory { + fun instanceOf(c: Class) : T +} + +class ContributorFactory : IFactory { + override fun instanceOf(c: Class) : T = Kobalt.INJECTOR.getInstance(c) +} + +///// +// XML parsing +// +// The following classes are used by JAXB to parse the plugin.xml file. + +/** + * The root element of plugin.xml + */ +@XmlRootElement(name = "kobalt-plugin") +class KobaltPluginXml { + @XmlElement @JvmField + var name: String? = null + + @XmlElement(name = "factory-class-name") @JvmField + var factoryClassName: String? = null + + @XmlElement(name = "classpath-contributors") @JvmField + var classpathContributors : ContributorsXml? = null + + @XmlElement(name = "project-contributors") @JvmField + var projectContributors : ContributorsXml? = null +} + +class ContributorXml { + @XmlElement @JvmField + val name: String? = null +} + +class ContributorsXml { + @XmlElement(name = "class-name") @JvmField + var className: List = arrayListOf() +} + +/** + * Turn a KobaltPluginXml (the raw content of plugin.xml) into a PluginInfo object, which contains + * all the contributors instantiated and other information that Kobalt can actually use. + */ +class PluginInfo(val xml: KobaltPluginXml) { + val projectContributors = arrayListOf() + val classpathContributors = arrayListOf() + // Future contributors: + // compilerArgs + // source files + // compilers + // --init + + companion object { + /** + * Read Kobalt's own plugin.xml. + */ + fun readKobaltPluginXml() : PluginInfo { + val pluginXml = KFiles.joinDir("META-INF", "plugin.xml") // Plugins.PLUGIN_XML) + val url = Kobalt::class.java.classLoader.getResource(pluginXml) + if (url != null) { + return readPluginXml(url.openConnection().inputStream) + } else { + throw AssertionError("Couldn't find $pluginXml") + } + } + + /** + * Read a general plugin.xml. + */ + private fun readPluginXml(ins: InputStream): PluginInfo { + val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java) + val kotlinPlugin: KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(ins) + as KobaltPluginXml + return PluginInfo(kotlinPlugin) + } + } + + init { + val factory = Class.forName(xml.factoryClassName).newInstance() as IFactory + xml.classpathContributors?.className?.forEach { + classpathContributors.add(factory.instanceOf(Class.forName(it)) as IClasspathContributor) + } + xml.projectContributors?.className?.forEach { + projectContributors.add(factory.instanceOf(Class.forName(it)) as IProjectContributor) + } + } +} + diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt index 69501c41..8cbe2f4c 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt @@ -2,7 +2,6 @@ package com.beust.kobalt.internal.remote import com.beust.kobalt.Args import com.beust.kobalt.api.PluginInfo -import com.beust.kobalt.api.PluginInfoDescription import com.beust.kobalt.kotlin.BuildFile import com.beust.kobalt.kotlin.BuildFileCompiler import com.beust.kobalt.maven.DependencyManager @@ -26,11 +25,11 @@ import javax.inject.Inject */ class GetDependenciesCommand @Inject constructor(val executors: KobaltExecutors, val buildFileCompilerFactory: BuildFileCompiler.IFactory, val args: Args, - val dependencyManager: DependencyManager, val pluginInfoDescription: PluginInfoDescription) : ICommand { + val dependencyManager: DependencyManager, val pluginInfo: PluginInfo) : ICommand { override val name = "getDependencies" override fun run(sender: ICommandSender, received: JsonObject) { val buildFile = BuildFile(Paths.get(received.get("buildFile").asString), "GetDependenciesCommand") - val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile), PluginInfo(pluginInfoDescription)) + val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) scriptCompiler.observable.subscribe { buildScriptInfo -> if (buildScriptInfo.projects.size > 0) { sender.sendData(toData(buildScriptInfo)) diff --git a/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt b/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt index bcb21dfe..1e4f7f03 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/MainModule.kt @@ -1,6 +1,7 @@ package com.beust.kobalt.misc import com.beust.kobalt.Args +import com.beust.kobalt.api.PluginInfo import com.beust.kobalt.kotlin.BuildFileCompiler import com.beust.kobalt.maven.* import com.beust.kobalt.plugin.publish.JCenterApi @@ -9,7 +10,6 @@ import com.google.inject.BindingAnnotation import com.google.inject.Provider import com.google.inject.TypeLiteral import com.google.inject.assistedinject.FactoryModuleBuilder -import java.lang.annotation.RetentionPolicy import java.util.concurrent.ExecutorService //@Singleton @@ -49,9 +49,12 @@ public open class MainModule(val args: Args) : AbstractModule() { bind(object: TypeLiteral() {}).toInstance(executors) bind(object: TypeLiteral() {}).annotatedWith(DependencyExecutor::class.java) .toInstance(executors.dependencyExecutor) - bind(Args::class.java).toProvider(object : Provider { + bind(Args::class.java).toProvider(object: Provider { override fun get(): Args? = args }) + bind(PluginInfo::class.java).toProvider(object: Provider { + override fun get(): PluginInfo? = PluginInfo.readKobaltPluginXml() + }) // bindListener(Matchers.any(), object: TypeListener {