diff --git a/build.gradle.kts b/build.gradle.kts index 1bae4d3..7bb98db 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("com.cognifide.gradle:common-plugin:0.1.64") + implementation("com.cognifide.gradle:common-plugin:0.1.63") implementation("org.buildobjects:jproc:2.3.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5") implementation("org.apache.commons:commons-lang3:3.9") @@ -56,6 +56,11 @@ val check by tasks.getting(Task::class) { } tasks { + jar { + dependsOn(":hosts:jar") + from(provider { project(":hosts").tasks.getByName("jar") }) + } + register("sourcesJar") { archiveClassifier.set("sources") dependsOn("classes") diff --git a/gradle.properties b/gradle.properties index 7bf8d81..cadfe26 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=1.0.9 +version=1.1.0 release.useAutomaticVersion=true \ No newline at end of file diff --git a/hosts/build.gradle.kts b/hosts/build.gradle.kts new file mode 100644 index 0000000..f667757 --- /dev/null +++ b/hosts/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + kotlin("jvm") + application + java +} + +description = "Hosts Editor" +version = "" + +repositories { + jcenter() +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") +} + +application { + mainClass.set("MainKt") +} + +tasks { + jar { + manifest { + attributes["Implementation-Title"] = project.description + attributes["Main-Class"] = "MainKt" + } + from(configurations.runtimeClasspath.get().files.map { if (it.isDirectory) it else zipTree(it) }) + } +} diff --git a/hosts/src/main/kotlin/main.kt b/hosts/src/main/kotlin/main.kt new file mode 100644 index 0000000..3bf3c56 --- /dev/null +++ b/hosts/src/main/kotlin/main.kt @@ -0,0 +1,66 @@ +import java.io.File + +fun main(args: Array) = try { + val sourceName = args.getOrNull(0) ?: "mysite" + val sourceFile = File(args.getOrNull(1) ?: ".gradle/environment/hosts.txt") + val sourceSection = Section(sourceName, sourceFile.readText().lines().map { it.trim() }) + val targetFile = File(args.getOrNull(2) ?: "/etc/hosts") + + val text = targetFile.readText() + val sections = Section.parseAll(text) + + val targetSection = sections.find { it.name == sourceSection.name } + + if (targetSection != null) { + targetFile.writeText(text.replace(targetSection.render(), sourceSection.render())) + } else { + targetFile.appendText("${System.lineSeparator()}${sourceSection.render()}") + } +} catch (e: Exception) { + println("Cannot update hosts file!") + println("Ensure using administrator/super-user privileges.") + println("Error details: ${e.message}") +} + +data class Section(val name: String, val entries: List) { + fun render() = mutableListOf().apply { + add("#environment-start") + add("#name=$name") + addAll(entries) + add("#environment-end") + }.joinToString(System.lineSeparator()) + + companion object { + fun parseAll(text: String): List
{ + val sections = mutableListOf
() + + var section = false + var sectionName = "" + val sectionLines = mutableListOf() + + text.lineSequence().forEach { line -> + when (val l = line.trim()) { + "#environment-start" -> { + section = true + } + "#environment-end" -> { + sections.add(Section(sectionName, sectionLines.toList())) + section = false + sectionLines.clear() + } + else -> { + if (section) { + if (l.startsWith("#name=")) { + sectionName = l.substringAfter("#name=") + } else { + sectionLines.add(l) + } + } + } + } + } + + return sections + } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 52ab668..4e33f3e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,3 @@ rootProject.name = "environment-plugin" + +include(":hosts") \ No newline at end of file diff --git a/src/main/kotlin/com/cognifide/gradle/environment/hosts/Host.kt b/src/main/kotlin/com/cognifide/gradle/environment/hosts/Host.kt index 3946645..fb2ab95 100644 --- a/src/main/kotlin/com/cognifide/gradle/environment/hosts/Host.kt +++ b/src/main/kotlin/com/cognifide/gradle/environment/hosts/Host.kt @@ -11,14 +11,7 @@ class Host(val url: String) { val config = URL(url) - init { - if (url.isBlank()) { - throw EnvironmentException("Host URL cannot be blank!") - } - } - - val text: String - get() = "$ip\t${config.host}" + val text: String get() = "$ip\t${config.host}" fun tag(id: String) { tags.add(id) @@ -30,5 +23,11 @@ class Host(val url: String) { fun tag(vararg ids: String) = tag(ids.asIterable()) + init { + if (url.isBlank()) { + throw EnvironmentException("Host URL cannot be blank!") + } + } + override fun toString(): String = "Host(url='$url', ip='$ip', tags=$tags)" } diff --git a/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostOptions.kt b/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostOptions.kt index 38a82e7..df0b44f 100644 --- a/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostOptions.kt +++ b/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostOptions.kt @@ -1,14 +1,14 @@ package com.cognifide.gradle.environment.hosts -import com.cognifide.gradle.environment.EnvironmentExtension +import com.cognifide.gradle.common.utils.using import com.cognifide.gradle.environment.EnvironmentException -import org.gradle.internal.os.OperatingSystem +import com.cognifide.gradle.environment.EnvironmentExtension import java.io.Serializable /** * Manages host definitions in case of different purposes indicated by tags. */ -class HostOptions(environment: EnvironmentExtension) : Serializable { +class HostOptions(private val environment: EnvironmentExtension) : Serializable { val docker = environment.docker @@ -22,17 +22,6 @@ class HostOptions(environment: EnvironmentExtension) : Serializable { convention(common.obj.provider { docker.runtime.hostIp }) } - val osFile = common.obj.string { - convention(common.obj.provider { - when { - OperatingSystem.current().isWindows -> """C:\Windows\System32\drivers\etc\hosts""" - else -> "/etc/hosts" - } - }) - } - - val appendix: String get() = defined.get().joinToString("\n") { it.text } - operator fun String.invoke(options: Host.() -> Unit = {}) = define(this, options) operator fun String.invoke(vararg tags: String) = define(this) { tag(tags.asIterable()) } @@ -61,4 +50,10 @@ class HostOptions(environment: EnvironmentExtension) : Serializable { fun all(tags: Iterable) = defined.get().filter { h -> tags.all { t -> h.tags.contains(t) } }.ifEmpty { throw EnvironmentException("Environment has no hosts tagged with '${tags.joinToString(",")}'!") } + + val updater by lazy { HostUpdater(environment) } + + fun updater(options: HostUpdater.() -> Unit) = updater.using(options) + + fun update() = updater.update() } diff --git a/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostUpdater.kt b/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostUpdater.kt new file mode 100644 index 0000000..1177441 --- /dev/null +++ b/src/main/kotlin/com/cognifide/gradle/environment/hosts/HostUpdater.kt @@ -0,0 +1,89 @@ +package com.cognifide.gradle.environment.hosts + +import com.cognifide.gradle.environment.EnvironmentExtension +import org.gradle.internal.os.OperatingSystem + +class HostUpdater(val environment: EnvironmentExtension) { + + private val project = environment.project + + private val logger = project.logger + + private val common = environment.common + + val interactive = common.obj.boolean { + convention(true) + common.prop.boolean("environment.hosts.updater.interactive")?.let { set(it) } + } + + val workDir = common.obj.dir { + convention(environment.rootDir.dir("hosts")) + common.prop.file("environment.hosts.updater.workDir")?.let { set(it) } + } + + val targetFile = common.obj.file { + fileProvider(common.obj.provider { + project.file(when { + OperatingSystem.current().isWindows -> """C:\Windows\System32\drivers\etc\hosts""" + else -> "/etc/hosts" + }) + }) + common.prop.file("environment.hosts.updater.targetFile")?.let { set(it) } + } + + val section = common.obj.string { + convention(environment.docker.stack.internalName) + common.prop.string("environment.hosts.updater.section")?.let { set(it) } + } + + @Suppress("MaxLineLength") + fun update() { + val os = OperatingSystem.current() + val osFile = targetFile.get() + + val dir = workDir.get().asFile.apply { mkdirs() } + + val entriesFile = dir.resolve("hosts.txt").apply { + logger.info("Generating hosts entries file: $this") + writeText(environment.hosts.defined.get().joinToString(System.lineSeparator()) { it.text }) + } + val updaterJar = dir.resolve("hosts.jar").apply { + logger.info("Providing hosts updater program: $this") + outputStream().use { output -> + this@HostUpdater.javaClass.getResourceAsStream("/hosts.jar").use { + input -> input.copyTo(output) + } + } + } + val sectionName = section.get() + + if (os.isWindows && interactive.get()) { + val scriptFile = dir.resolve("hosts.bat") + logger.info("Generating hosts updating script: $scriptFile") + + scriptFile.writeText(""" + powershell -command "Start-Process cmd -ArgumentList '/C cd %CD% && java -jar $updaterJar $sectionName $entriesFile $osFile' -Verb runas" + """.trimIndent()) + project.exec { it.commandLine("cmd", "/C", scriptFile.toString()) } + logger.lifecycle("Environment hosts successfully updated.") + } else { + val scriptFile = dir.resolve("hosts.sh") + logger.info("Generating hosts updating script: $scriptFile") + + if (os.isMacOsX && interactive.get()) { + scriptFile.writeText(""" + #!/bin/sh + osascript -e "do shell script \"java -jar $updaterJar $sectionName $entriesFile $osFile\" with prompt \"Gradle Environment Hosts\" with administrator privileges" + """.trimIndent()) + project.exec { it.commandLine("sh", scriptFile.toString()) } + logger.lifecycle("Environment hosts successfully updated.") + } else { + scriptFile.writeText(""" + #!/bin/sh + java -jar $updaterJar $sectionName $entriesFile $osFile + """.trimIndent()) + logger.lifecycle("To update environment hosts, run script below as administrator/super-user:\n$scriptFile") + } + } + } +} diff --git a/src/main/kotlin/com/cognifide/gradle/environment/tasks/EnvironmentHosts.kt b/src/main/kotlin/com/cognifide/gradle/environment/tasks/EnvironmentHosts.kt index 0ad3191..b7a1842 100644 --- a/src/main/kotlin/com/cognifide/gradle/environment/tasks/EnvironmentHosts.kt +++ b/src/main/kotlin/com/cognifide/gradle/environment/tasks/EnvironmentHosts.kt @@ -7,12 +7,11 @@ open class EnvironmentHosts : EnvironmentDefaultTask() { @TaskAction fun appendHosts() { - logger.lifecycle("Hosts entries to be appended to ${environment.hosts.osFile.get()}:") - logger.quiet(environment.hosts.appendix) + environment.hosts.update() } init { - description = "Prints environment hosts entries." + description = "Updates environment hosts entries." } companion object {