You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
3.8 KiB

package de.joshavg
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import javax.enterprise.context.ApplicationScoped
import javax.inject.Inject
@ApplicationScoped
class GitRunner(
@Inject
val builds: Builds,
@Inject
val handles: Handles
) {
fun run(buildId: BuildId, rev: String): ProcessInfo {
val config = builds.buildConfig(buildId)
val logFile = builds.createLogFile(buildId)
logger.info("preparing process for build $buildId with config ${config.asPublic()}")
logger.info("log file: $logFile")
logFileHeader(logFile, buildId, rev)
assertEmptyWorkspace(config)
Thread {
try {
clone(config, logFile, config.gitRepo!!, rev, buildId)
execScripts(config, logFile, rev, buildId)
} finally {
cleanupWorkspace(config, buildId)
}
}.start()
return ProcessInfo(-1, logFile)
}
private fun clone(
config: BuildConfig,
logFile: File,
gitRepo: String,
rev: String,
buildId: BuildId
) {
logger.info("build $buildId: cloning ${config.gitRepo} into ${config.workspace}")
val process = processBuilder(config, logFile, "")
.command("git", "clone", config.gitRepo, ".")
.start()
handles.add(Handle(process.toHandle(), buildId))
val cloneSuccess = process.waitFor(30, TimeUnit.SECONDS)
logger.info("build $buildId: checkout rev $rev")
processBuilder(config, logFile, "")
.command("git", "checkout", rev)
.start()
.waitFor()
if (!cloneSuccess) {
throw FailedToClone(buildId, gitRepo)
}
}
private fun execScripts(config: BuildConfig, logFile: File, rev: String, buildId: BuildId) {
val scriptFiles = listOf("pre.sh", "job.sh", "post.sh")
logger.info("build $buildId: looking for scripts $scriptFiles in .alfred/")
scriptFiles.forEach { script ->
if (Paths.get(config.workspace, ".alfred", script).toFile().exists()) {
logger.info("build $buildId: found script $script, running it")
val scriptProcess = processBuilder(config, logFile, rev)
.command(".alfred/$script")
.start()
handles.add(Handle(scriptProcess.toHandle(), buildId))
val ret = scriptProcess.waitFor()
logger.info("build $buildId: script $script returned $ret")
logFile.appendText("\n$script returned $ret\n")
}
}
}
private fun cleanupWorkspace(config: BuildConfig, buildId: BuildId) {
val wsList = File(config.workspace).list()
if (wsList != null && wsList.isNotEmpty()) {
logger.info("build $buildId: cleaning up workspace ${config.workspace}")
val ws = File(config.workspace)
ws.deleteRecursively()
ws.mkdirs()
}
}
private fun assertEmptyWorkspace(config: BuildConfig) {
val workspace = File(config.workspace)
if (!workspace.exists()) {
workspace.mkdirs()
}
val wsList = workspace.list()
if (wsList != null && wsList.isNotEmpty()) {
throw WorkspaceIsNotEmpty(config.workspace)
}
}
val logger: Logger = LoggerFactory.getLogger(this::class.java)
}
class WorkspaceIsNotEmpty(
private val ws: String
) : RuntimeException() {
override fun toString() =
"${this::class}: workspace $ws is not empty"
}
class FailedToClone(
private val buildId: BuildId,
private val gitRepo: String
) : RuntimeException() {
override fun toString() =
"${this::class}: failed to clone $gitRepo for build id $buildId"
}