From 8ce34cfd6e24bc9232bee4206d2aebbca64723d7 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 15 May 2024 17:48:24 +0600 Subject: [PATCH] add templating script --- README.md | 45 ++++++ build.gradle.kts | 10 +- controls-constructor/README.ktstemplate.md | 25 ++++ ktstemplate_generator.kts | 151 +++++++++++++++++++++ 4 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 controls-constructor/README.ktstemplate.md create mode 100644 ktstemplate_generator.kts diff --git a/README.md b/README.md index d6a602b..080fce8 100644 --- a/README.md +++ b/README.md @@ -226,3 +226,48 @@ the current time. The device is configurable via a simple TornadoFX-based contro You can run a demo by executing `application/run` Gradle task. The graphs are displayed using [plotly.kt](https://github.com/mipt-npm/plotly.kt) library. + +## Templates + +**This feature required `kotlin` to be installed in your system. [Read more](https://kotlinlang.org/docs/command-line.html#install-the-compiler)** + +**You may run gradle task `generateKTStemplates` instead of raw launch, but it will work slowly. Sample `./gradlew generateKTStemplates`** + +This project supports generating of files from `.ktstemplate.` files. Current docs: + +### Using + +* Create file contains `.ktstemplate` in its name +* Write variables **before** the first `H*` (starting with `#`) section +* Launch `kotlin ${thisscriptname}` with required args + +#### File sample + +```markdown +first = hello +second = world + +# Sample + +This is sample of $first $second +``` + +Will have next result: + +```markdown +# Sample + +This is sample of hello world +``` + +### Launch + +This script accept next args: + +`[...paths] [--plain] [--recursive]` + +Where: + +* `...paths` - Paths to the files-templates or folders with files-templates +* `--plain` - will look only into the folders from `paths` +* `--recursive` - (default) will look into the folders from `paths` and recursively in subfolders diff --git a/build.gradle.kts b/build.gradle.kts index 38d5c6a..ea87aaa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,4 +22,12 @@ ksciencePublish { sonatype("https://oss.sonatype.org") } -readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") \ No newline at end of file +readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") + +task("generateKTStemplates") { + doLast { + exec { + commandLine("kotlin", "ktstemplate_generator.kts") + } + } +} \ No newline at end of file diff --git a/controls-constructor/README.ktstemplate.md b/controls-constructor/README.ktstemplate.md new file mode 100644 index 0000000..b4937ba --- /dev/null +++ b/controls-constructor/README.ktstemplate.md @@ -0,0 +1,25 @@ +package_group=space.kscience +package_name=controls-constructor +maven_url=https://maven.sciprog.center + +# Module controls-constructor + +A low-code constructor for composite devices simulation + +## Usage + +## Artifact: + +The Maven coordinates of this project are `$package_group:$package_name:0.3.0`. + +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("$package_group:$package_name:0.3.0") +} +``` diff --git a/ktstemplate_generator.kts b/ktstemplate_generator.kts new file mode 100644 index 0000000..d0124a1 --- /dev/null +++ b/ktstemplate_generator.kts @@ -0,0 +1,151 @@ +/** + * # Generating files from templates script + * + * ## Using + * + * * Create file contains `.ktstemplate` in its name + * * Write variables **before** the first H* (starting with `#`) section + * * Launch `kotlin ${thisscriptname}` with required args + * + * ### File sample + * + * ```markdown + * first = hello + * second = world + * + * # Sample + * + * This is sample of $first $second + * ``` + * + * Will have next result: + * + * ```markdown + * # Sample + * + * This is sample of hello world + * ``` + * + * ## Launch + * + * This script accept next args: + * + * `[...paths] [--plain] [--recursive]` + * + * Where: + * + * * `...paths` - Paths to the files-templates or folders with files-templates + * * `--plain` - will look only into the folders from `paths` + * * `--recursive` - (default) will look into the folders from `paths` and recursively in subfolders + */ +import kotlin.collections.LinkedHashSet +import java.io.File + +val templateEnding = Regex("\\.ktstemplate(\\.[^\\.]*)*$") +val templateOnlyEnding = Regex("\\.ktstemplate") +val singleArgumentRegex = Regex("^[\\w\\d]+$") +val splitterRegex = Regex("[ ]*=[ ]*") + +sealed interface Mode { + fun filesList(folder: File): Sequence + + data object Recursive : Mode { + override fun filesList(folder: File): Sequence { + return sequence { + val folders = mutableListOf() + folders.add(folder) + while (folders.isNotEmpty()) { + val currentFolder = folders.removeAt(0) + currentFolder.listFiles().toList().forEach { + when { + it.isFile -> yield(it) + it.isDirectory -> folders.add(it) + } + } + } + } + } + } + + data object Plain : Mode { + override fun filesList(folder: File): Sequence { + return sequence { + folder.listFiles().forEach { + yield(it) + } + } + } + } +} +var mode: Mode = Mode.Recursive + +val folders = args.mapNotNull { + if (it.startsWith("-")) { // assume some arg + when (it) { + "--plain" -> mode = Mode.Plain + "--recursive" -> mode = Mode.Recursive + "--help" -> { + println("[...pathnames] [--recursive] [--plain]") + println("...pathnames - Pass any count of folder or files paths") + println("--recursive - (default) Use recursive visiting of folders for each path in pathnames") + println("--plain - (default) Use plain (non-recursive) visiting of folders for each path in pathnames") + } + } + null + } else { + File(it) + } +}.ifEmpty { + listOf(File("./")) +} + +fun String.replaceVariables(variables: Map): String { + var currentLine = this + variables.forEach { (k, v) -> + currentLine = currentLine.replace("\${${k}}", v) + if (k.matches(singleArgumentRegex)) { + currentLine = currentLine.replace("\$${k}", v) + } + } + return currentLine +} + +fun generateFromTemplate(folder: File, file: File) { + val targetFile = File(folder, file.name.replace(templateOnlyEnding, "")) + + val variables = mutableMapOf() + var writeVariables = true + var text = "" + + file.readLines().forEach { line -> + when { + writeVariables && line.startsWith("#") -> { + writeVariables = false + } + writeVariables -> { + val splitted = line.split(splitterRegex) + if (splitted.size > 1) { + val k = splitted[0] + val v = splitted[1].replaceVariables(variables) + variables[k] = v + } + return@forEach + } + } + text += line.let { + line.replaceVariables(variables) + "\n" + } + } + targetFile.writeText(text) + println("${targetFile.absolutePath} has been recreated") +} + +if (args.none { it == "--help" }) { + folders.forEach { folder -> + mode.filesList(folder).forEach { file -> + if (file.name.contains(templateEnding)) { + generateFromTemplate(file.parentFile, file) + } + } + } +}