From d5e6a04b5d465d0df56c75c6b8e85dd6e4b1a897 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 16 Feb 2016 18:07:18 -0800 Subject: [PATCH] KobaltPlugin template. --- .../com/beust/kobalt/api/IInitContributor.kt | 5 ++ .../com/beust/kobalt/app/JarTemplate.kt | 49 ++++++++++++++++++ .../beust/kobalt/app/KobaltPluginTemplate.kt | 19 +++++++ .../com/beust/kobalt/app/ProjectGenerator.kt | 2 +- .../resources/META-INF/kobalt-core-plugin.xml | 3 ++ src/main/resources/templates/plugin.jar | Bin 0 -> 11887 bytes 6 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/com/beust/kobalt/app/JarTemplate.kt create mode 100644 src/main/kotlin/com/beust/kobalt/app/KobaltPluginTemplate.kt create mode 100644 src/main/resources/templates/plugin.jar diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IInitContributor.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IInitContributor.kt index 18eb7ea0..0645f5aa 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IInitContributor.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/api/IInitContributor.kt @@ -27,6 +27,11 @@ interface IArchetype { */ val pluginName: String + /** + * Instructions to display to the user after a template has been generated. + */ + val instructions : String get() = "Build this project with `./kobaltw assemble`" + /** * Generate the files for this archetype. The parameter is the arguments that were passed to the kobaltw * command. diff --git a/src/main/kotlin/com/beust/kobalt/app/JarTemplate.kt b/src/main/kotlin/com/beust/kobalt/app/JarTemplate.kt new file mode 100644 index 00000000..6dc3b0b2 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/app/JarTemplate.kt @@ -0,0 +1,49 @@ +package com.beust.kobalt.app + +import com.beust.kobalt.Args +import com.beust.kobalt.api.IArchetype +import com.beust.kobalt.misc.log +import java.io.File +import java.io.FileOutputStream +import java.util.jar.JarInputStream + +/** + * Base class for templates that simply decompress a jar file to generate their project. + */ +abstract class JarTemplate(val jarName: String) : IArchetype { + companion object { + fun extractFile(ins: JarInputStream, destDir: File) { + var entry = ins.nextEntry + while (entry != null) { + val f = File(destDir.path + File.separator + entry.name) + if (entry.isDirectory) { + f.mkdir() + entry = ins.nextEntry + continue + } + + log(2, "Extracting: $entry to ${f.absolutePath}") + FileOutputStream(f).use { fos -> + var read = ins.read() + while (ins.available() > 0 && read != -1) { + fos.write(read) + read = ins.read() + } + } + entry = ins.nextEntry + } + } + + fun log(level: Int, s: String) { + println(" " + s) + } + } + + override fun generateArchetype(args: Args, classLoader: ClassLoader) { + log(1, "Generating archetype for Android with class loader $classLoader") + val destDir = File(".") + val ins = JarInputStream(classLoader.getResource(jarName).openConnection().inputStream) + extractFile(ins, destDir) + } + +} diff --git a/src/main/kotlin/com/beust/kobalt/app/KobaltPluginTemplate.kt b/src/main/kotlin/com/beust/kobalt/app/KobaltPluginTemplate.kt new file mode 100644 index 00000000..548ff11c --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/app/KobaltPluginTemplate.kt @@ -0,0 +1,19 @@ +package com.beust.kobalt.app + +import com.beust.kobalt.api.IInitContributor +import com.beust.kobalt.plugin.KobaltPlugin + +/** + * Template that generates a Kobalt plug-in project. + */ +class KobaltPluginTemplate : IInitContributor { + val pluginArchetype = object: JarTemplate("templates/plugin.jar") { + override val archetypeDescription = "Generate a sample Kobalt plug-in project" + + override val archetypeName = "kobalt-plugin" + + override val pluginName = KobaltPlugin.PLUGIN_NAME + } + + override val archetypes = listOf(pluginArchetype) +} diff --git a/src/main/kotlin/com/beust/kobalt/app/ProjectGenerator.kt b/src/main/kotlin/com/beust/kobalt/app/ProjectGenerator.kt index 467d7f93..a8bd9e48 100644 --- a/src/main/kotlin/com/beust/kobalt/app/ProjectGenerator.kt +++ b/src/main/kotlin/com/beust/kobalt/app/ProjectGenerator.kt @@ -2,7 +2,6 @@ package com.beust.kobalt.app import com.beust.kobalt.Args import com.beust.kobalt.api.IArchetype -import com.beust.kobalt.api.IInitContributor import com.beust.kobalt.internal.PluginInfo import com.beust.kobalt.misc.log import com.beust.kobalt.misc.warn @@ -27,6 +26,7 @@ class ProjectGenerator @Inject constructor(val pluginInfo: PluginInfo){ if (archetype != null) { log(2, "Running archetype $archetypeName") archetype.generateArchetype(args, classLoader) + log(1, "\n\n" + archetype.instructions) } else { warn("Couldn't find any archetype named $archetypeName") } diff --git a/src/main/resources/META-INF/kobalt-core-plugin.xml b/src/main/resources/META-INF/kobalt-core-plugin.xml index e4e467cb..9ff1bd10 100644 --- a/src/main/resources/META-INF/kobalt-core-plugin.xml +++ b/src/main/resources/META-INF/kobalt-core-plugin.xml @@ -21,5 +21,8 @@ com.beust.kobalt.internal.TestNgRunner com.beust.kobalt.internal.SpekRunner + + com.beust.kobalt.app.KobaltPluginTemplate + \ No newline at end of file diff --git a/src/main/resources/templates/plugin.jar b/src/main/resources/templates/plugin.jar new file mode 100644 index 0000000000000000000000000000000000000000..8d8683a6b760f67634d5d94e80edd9a869816798 GIT binary patch literal 11887 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 literal 0 HcmV?d00001