diff --git a/src/main/kotlin/com/cognifide/gradle/environment/docker/Docker.kt b/src/main/kotlin/com/cognifide/gradle/environment/docker/Docker.kt index 059f6a1..1def316 100644 --- a/src/main/kotlin/com/cognifide/gradle/environment/docker/Docker.kt +++ b/src/main/kotlin/com/cognifide/gradle/environment/docker/Docker.kt @@ -5,7 +5,9 @@ import com.cognifide.gradle.common.utils.using import com.cognifide.gradle.environment.EnvironmentExtension import kotlinx.coroutines.* import org.apache.commons.io.output.TeeOutputStream +import org.gradle.api.provider.Provider import org.gradle.process.internal.streams.SafeStreams +import java.io.File import java.io.FileOutputStream class Docker(val environment: EnvironmentExtension) { @@ -267,4 +269,20 @@ class Docker(val environment: EnvironmentExtension) { logger.lifecycle("Stopped Docker daemon \"$operation\"") } + + @Suppress("TooGenericExceptionCaught") + fun load(file: File): String { + val output = DockerProcess().execString { + withArgs("load", "--input", file.absolutePath) + } + return output.lineSequence().firstOrNull { it.startsWith("Loaded image:") } + ?.substringAfter(":")?.trim() + ?: throw DockerException("Cannot determine loaded Docker image name from output:\n$output\n") + } + + fun load(composePropertyName: String, fileProvider: () -> File) = load(composePropertyName, common.project.provider { fileProvider() }) + + fun load(composePropertyName: String, fileProvider: Provider) { + composeProperties.putAll(common.project.provider { mapOf(composePropertyName to load(fileProvider.get())) }) + } } diff --git a/src/main/kotlin/com/cognifide/gradle/environment/docker/stack/Compose.kt b/src/main/kotlin/com/cognifide/gradle/environment/docker/stack/Compose.kt index e999316..a4d40fe 100644 --- a/src/main/kotlin/com/cognifide/gradle/environment/docker/stack/Compose.kt +++ b/src/main/kotlin/com/cognifide/gradle/environment/docker/stack/Compose.kt @@ -38,6 +38,7 @@ class Compose(environment: EnvironmentExtension) : Stack(environment) { val processBuilder = common.obj.typed { convention(common.obj.provider { ComposeProcessBuilder.detect() }) + finalizeValueOnRead() common.prop.string("docker.compose.processBuilder")?.let { set(ComposeProcessBuilder.of(it)) } } @@ -60,6 +61,11 @@ class Compose(environment: EnvironmentExtension) : Stack(environment) { var deployRetry = common.retry { afterSecond(common.prop.long("docker.compose.deployRetry") ?: 30) } + val deployArgs = common.obj.strings { + convention(listOf("--remove-orphans")) + common.prop.list("docker.compose.deployArgs")?.let { set(it) } + } + override fun deploy() { init() @@ -68,7 +74,7 @@ class Compose(environment: EnvironmentExtension) : Stack(environment) { try { process().exec { - withArgs("-p", internalName.get(), "-f", composeFilePath, "up", "-d") + withArgs("-p", internalName.get(), "-f", composeFilePath, "up", "-d", *deployArgs.get().toTypedArray()) } } catch (e: DockerException) { throw StackException("Failed to deploy Docker Compose stack '${internalName.get()}'!", e) @@ -88,13 +94,18 @@ class Compose(environment: EnvironmentExtension) : Stack(environment) { var undeployRetry = common.retry { afterSecond(common.prop.long("docker.compose.undeployRetry") ?: 30) } + val undeployArgs = common.obj.strings { + convention(listOf("--remove-orphans")) + common.prop.list("docker.compose.undeployArgs")?.let { set(it) } + } + override fun undeploy() { init() common.progressIndicator { message = "Stopping stack '${internalName.get()}'" - val args = arrayOf("-p", internalName.get(), "-f", composeFilePath, "down") + val args = arrayOf("-p", internalName.get(), "-f", composeFilePath, "down", *undeployArgs.get().toTypedArray()) try { process().exec { withArgs(*args) } } catch (e: DockerException) { @@ -118,18 +129,31 @@ class Compose(environment: EnvironmentExtension) : Stack(environment) { override fun troubleshoot(): List = mutableListOf().apply { add("Consider troubleshooting:") + val process = process() val psArgs = arrayOf("-p", internalName.get(), "ps") + val logsArgs = arrayOf("-p", internalName.get(), "logs") + try { - val out = try { + add("* restarting Docker") + + val psOut = try { process().execString { withArgs(*psArgs) } } catch (e: Exception) { throw StackException("Cannot list processes in Docker Compose stack named '${internalName.get()}'!", e) } - add("* restarting Docker") - add("* using output of command: 'docker ${psArgs.joinToString(" ")}':\n") - add(out) + add("* using output of command: '${(process.commandLine + psArgs).joinToString(" ")}':\n") + add(psOut + "\n") + + val logsOut = try { + process().execString { withArgs(*logsArgs) } + } catch (e: Exception) { + throw StackException("Cannot print logs from Docker Compose stack named '${internalName.get()}'!", e) + } + add("* using output of command: '${(process.commandLine + logsArgs).joinToString(" ")}':\n") + add(logsOut + "\n") } catch (e: Exception) { - add("* using command: 'docker ${psArgs.joinToString(" ")}'") + add("* using command: '${(process.commandLine + psArgs).joinToString(" ")}'") + add("* using command: '${(process.commandLine + logsArgs).joinToString(" ")}'") add("* restarting Docker") } }