1
0

Add features + ktlint as first feature

This commit is contained in:
Hubert Van De Walle 2020-10-08 15:35:25 +02:00
parent aa585358be
commit 68fdac4d64
15 changed files with 177 additions and 54 deletions

View File

@ -16,6 +16,11 @@ display = "Java Version"
default = "1.4.10"
display = "Kotlin Version"
[features]
[features.ktlint]
default = true
[versions]
http4k = "3.265.0"
pebble = "3.1.4"

View File

@ -150,7 +150,6 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
@ -195,7 +194,6 @@
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

View File

@ -0,0 +1,51 @@
package pebble
import com.mitchellbosecke.pebble.extension.escaper.SafeString
import com.mitchellbosecke.pebble.template.EvaluationContext
import com.mitchellbosecke.pebble.template.PebbleTemplate
import org.intellij.lang.annotations.Language
import starter.Dependency
import starter.utils.PebbleFunction
// We need a custom function since pebble inserts whitespace everywhere
class DepAsXmlPebbleFunction : PebbleFunction {
override val name = "depAsXml"
override fun getArgumentNames() = listOf("dependency")
override fun execute(
args: Map<String, Any>,
self: PebbleTemplate,
context: EvaluationContext,
lineNumber: Int,
): SafeString {
val dep = args["dependency"] as Dependency
fun tagName(name: String) = """<span class="text-red-700">$name</span>"""
fun startTag(name: String): String {
@Language("html") @Suppress("UnnecessaryVariable")
val result = """<span class="text-gray-700">&lt;</span>""" +
"""${tagName(name)}<span class="text-gray-700">&gt;</span>"""
return result
}
fun endTag(name: String): String {
@Language("html") @Suppress("UnnecessaryVariable")
val result = """<span class="text-gray-700">&lt;/</span>""" +
"""${tagName(name)}<span class="text-gray-700">&gt;</span>"""
return result
}
fun tag(name: String, content: String) = """${startTag(name)}$content${endTag(name)}"""
val result = """
|${startTag("dependency")}
| ${tag("groupId", dep.groupId)}
| ${tag("artifactId", dep.artifactId)}
| ${tag("version", dep.version.value)}
|${endTag("dependency")}
""".trimMargin()
return SafeString(result)
}
}

View File

@ -0,0 +1,27 @@
package pebble
import com.mitchellbosecke.pebble.template.EvaluationContext
import com.mitchellbosecke.pebble.template.PebbleTemplate
import starter.Feature
import starter.utils.PebbleFilter
class HasFeatureFilter : PebbleFilter {
override val name = "hasFeature"
override fun getArgumentNames() = listOf("name")
override fun apply(
input: Any,
args: MutableMap<String, Any>,
self: PebbleTemplate,
context: EvaluationContext,
lineNumber: Int,
): Boolean {
@Suppress("UNCHECKED_CAST")
val features = input as List<Feature>
val name = args["name"] as String
return features.any { it.name == name }
}
}

View File

@ -24,10 +24,13 @@ data class Repository(val name: String, val url: String)
data class Input(val name: String, val display: String, val value: String? = null)
data class Feature(val name: String, val value: Boolean = false)
data class Project(
val name: String,
val basePackage: String,
val inputs: List<Input>,
val features: List<Feature>,
val dependencies: List<Dependency>,
val repositories: Collection<Repository>,
)

View File

@ -7,6 +7,7 @@ import com.electronwill.nightconfig.core.Config as NightConfig
data class StarterConfig(
val dependencies: List<Dependency>,
val inputs: List<Input>,
val features: List<Feature>,
)
class Config(private val cfg: NightConfig) {
@ -54,6 +55,11 @@ class Config(private val cfg: NightConfig) {
Input(name, values["display"], values["default"])
}
return StarterConfig(dependencies, inputs)
val features = cfg.configMap("features")
.map { (name, values) ->
Feature(name, values["default"] ?: false)
}
return StarterConfig(dependencies, inputs, features)
}
}

View File

@ -1,65 +1,23 @@
package starter.modules
import com.mitchellbosecke.pebble.extension.escaper.SafeString
import com.mitchellbosecke.pebble.template.EvaluationContext
import com.mitchellbosecke.pebble.template.PebbleTemplate
import org.intellij.lang.annotations.Language
import org.koin.dsl.bind
import org.koin.dsl.module
import starter.Dependency
import pebble.DepAsXmlPebbleFunction
import pebble.HasFeatureFilter
import starter.utils.PebbleEngineBuilder
import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap
import starter.utils.PebbleFilter
import starter.utils.PebbleFunction
class DepAsXmlPebbleFunction : PebbleFunction {
override val name = "depAsXml"
override fun getArgumentNames() = listOf("dependency")
override fun execute(
args: Map<String, Any>,
self: PebbleTemplate,
context: EvaluationContext,
lineNumber: Int,
): Any {
val dep = args["dependency"] as Dependency
fun tagName(name: String) = """<span class="text-red-700">$name</span>"""
fun startTag(name: String): String {
@Language("html") @Suppress("UnnecessaryVariable")
val result = """<span class="text-gray-700">&lt;</span>""" +
"""${tagName(name)}<span class="text-gray-700">&gt;</span>"""
return result
}
fun endTag(name: String): String {
@Language("html") @Suppress("UnnecessaryVariable")
val result = """<span class="text-gray-700">&lt;/</span>""" +
"""${tagName(name)}<span class="text-gray-700">&gt;</span>"""
return result
}
fun tag(name: String, content: String) = """${startTag(name)}$content${endTag(name)}"""
val result = """
|${startTag("dependency")}
| ${tag("groupId", dep.groupId)}
| ${tag("artifactId", dep.artifactId)}
| ${tag("version", dep.version.value)}
|${endTag("dependency")}
""".trimMargin()
return SafeString(result)
}
}
val pebbleModule = module {
single { DepAsXmlPebbleFunction() } bind PebbleFunction::class
single { HasFeatureFilter() } bind PebbleFilter::class
single {
PebbleEngineBuilder {
cache = ConcurrentMap
functions(getAll())
filters(getAll())
classPath { suffix = ".twig" }
}
}

View File

@ -25,13 +25,21 @@ class ZipRouteSupplier(
req.form(it.name) != null
}
val formMap = req.formAsMap()
val inputKeys = conf.inputs.map { it.name }
val inputs = req.formAsMap()
val inputs = formMap
.filter { it.key in inputKeys }
.map { (name, value) ->
conf.inputs.find { it.name == name }!!.copy(value = value.first())
}
val features = formMap
.filter { it.key in conf.features.map { it.name } }
.map { (name, _) ->
conf.features.find { it.name == name }!!.copy(value = true)
}
val projectName = inputs.find { it.name == "name" }!!.value!!
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
@ -39,7 +47,7 @@ class ZipRouteSupplier(
Response.badRequest()
} else {
val repositories = deps.mapNotNull { it.repository }.toSet()
val project = Project(projectName, basePackage, inputs, deps, repositories)
val project = Project(projectName, basePackage, inputs, features, deps, repositories)
val outputStream = projectZip.createZip(project)
Response.ok().with(

View File

@ -13,6 +13,7 @@ class PomTemplate(private val engine: PebbleEngine) : Template {
"dependencies" to project.dependencies.sortedBy { it.scope },
"repositories" to project.repositories,
"kotlinxSerialization" to project.dependencies.any { it.name == "kotlinx-serialization" },
"features" to project.features,
"versions" to project.dependencies.map { it.version }.toSet()
)
@ -20,6 +21,8 @@ class PomTemplate(private val engine: PebbleEngine) : Template {
args[it.name] = it.value
}
println(args.entries.joinToString("\n"))
val rendered = engine.render("starter/pom/index", args)
return prettyPrintXml(rendered)
}

View File

@ -7,7 +7,8 @@ import starter.utils.render
class Views(private val engine: PebbleEngine, config: StarterConfig) {
private val args = mapOf(
"dependencies" to config.dependencies.groupBy { it.category }.toSortedMap(),
"inputs" to config.inputs
"inputs" to config.inputs,
"features" to config.features,
)
fun index() = engine.render("views/index", args)

View File

@ -10,5 +10,7 @@
{% include "starter/pom/plugins/@shade" %}
{% include "starter/pom/plugins/@ktlint" %}
</plugins>
</build>
</build>

View File

@ -8,6 +8,7 @@
<properties>
<java.version>{{ javaVersion }}</java.version>
<kotlin.version>{{ kotlinVersion }}</kotlin.version>
<kotlin.code.style>official</kotlin.code.style>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -0,0 +1,46 @@
{% if features | hasFeature("ktlint") %}
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>ktlint</id>
<phase>verify</phase>
<configuration>
<target name="ktlint">
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
<arg value="src/**/*.kt"/>
</java>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>ktlint-format</id>
<configuration>
<target name="ktlint">
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
<arg value="-F"/>
<arg value="src/**/*.kt"/>
</java>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.pinterest</groupId>
<artifactId>ktlint</artifactId>
<version>0.39.0</version>
</dependency>
</dependencies>
</plugin>
{% endif %}

View File

@ -10,6 +10,19 @@
{% endfor %}
<div class="mt-4">
<section>
<h2 class="category">Features</h2>
<ul>
{% for feature in features %}
<label class="m-2">
<input name="{{ feature.name }}"
type="checkbox"{% if feature.value %} checked{% endif %}>
<span>{{ feature.name }}</span>
</label>
{% endfor %}
</ul>
</section>
{% for category in dependencies %}
<section>
<h2 class="category">{{ category.key }}</h2>

View File

@ -30,6 +30,7 @@ internal class PomTemplateTest {
name = "Test",
basePackage = "org.test",
inputs = conf.inputs,
features = emptyList(),
dependencies = conf.dependencies,
repositories = conf.dependencies.mapNotNull { it.repository }.toSet()
)