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.
155 lines
4.5 KiB
155 lines
4.5 KiB
package alfred.running
|
|
|
|
import alfred.BuildConfig
|
|
import alfred.BuildId
|
|
import alfred.Builds
|
|
import org.slf4j.Logger
|
|
import org.slf4j.LoggerFactory
|
|
import java.nio.file.Path
|
|
import java.nio.file.Paths
|
|
import java.util.*
|
|
import java.util.concurrent.TimeUnit
|
|
import javax.enterprise.context.ApplicationScoped
|
|
import javax.inject.Inject
|
|
|
|
@ApplicationScoped
|
|
class GitRunner {
|
|
|
|
@field:Inject
|
|
lateinit var builds: Builds
|
|
|
|
@field:Inject
|
|
lateinit var handles: Handles
|
|
|
|
val scriptsDir = ".alfred"
|
|
|
|
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")
|
|
logger.info("log file: $logFile")
|
|
|
|
val ctx = BuildContext(
|
|
buildId = buildId,
|
|
config = config,
|
|
wsId = UUID.randomUUID().toString(),
|
|
logFile = logFile,
|
|
rev = rev
|
|
)
|
|
|
|
logFile.header(buildId, rev, ctx.workspace)
|
|
|
|
assertEmptyWorkspace(ctx)
|
|
|
|
Thread {
|
|
try {
|
|
clone(ctx)
|
|
execScripts(ctx)
|
|
} finally {
|
|
deleteWorkspace(ctx)
|
|
logFile.footer()
|
|
}
|
|
}.start()
|
|
|
|
return ProcessInfo(-1, logFile)
|
|
}
|
|
|
|
private fun clone(ctx: BuildContext) {
|
|
logger.info("build ${ctx.buildId}: cloning ${ctx.config.gitRepo} into ${ctx.workspace}")
|
|
|
|
val process = processBuilder(ctx.config, ctx.logFile, "")
|
|
.command("git", "clone", ctx.config.gitRepo, ".")
|
|
.directory(ctx.workspace.toFile())
|
|
.start()
|
|
handles.add(Handle(process.toHandle(), ctx.buildId))
|
|
val cloneSuccess = process.waitFor(30, TimeUnit.SECONDS)
|
|
|
|
logger.info("build ${ctx.buildId}: checkout rev ${ctx.rev}")
|
|
processBuilder(ctx.config, ctx.logFile, "")
|
|
.command("git", "checkout", ctx.rev)
|
|
.directory(ctx.workspace.toFile())
|
|
.start()
|
|
.waitFor()
|
|
|
|
if (!cloneSuccess) {
|
|
throw FailedToClone(ctx.buildId, ctx.config.gitRepo ?: "[no repo configured]")
|
|
}
|
|
}
|
|
|
|
private fun execScripts(ctx: BuildContext) {
|
|
val scriptFiles = listOf("pre.sh", "job.sh", "post.sh")
|
|
|
|
logger.info("build ${ctx.buildId}: looking for scripts $scriptFiles in $scriptsDir/")
|
|
|
|
scriptFiles.forEach { script ->
|
|
if (shFile(ctx, script).exists()) {
|
|
logger.info("build ${ctx.buildId}: found script $script, running it")
|
|
|
|
ctx.logFile.append("\nRunning build file: $script\n")
|
|
|
|
val scriptProcess = processBuilder(ctx.config, ctx.logFile, ctx.rev)
|
|
.command("$scriptsDir/$script")
|
|
.directory(ctx.workspace.toFile())
|
|
.start()
|
|
handles.add(Handle(scriptProcess.toHandle(), ctx.buildId))
|
|
|
|
val ret = scriptProcess.waitFor()
|
|
logger.info("build ${ctx.buildId}: script $script returned $ret")
|
|
|
|
ctx.logFile.append("\n$script returned $ret\n")
|
|
} else {
|
|
ctx.logFile.append("\nBuild file $scriptsDir/$script not found\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun shFile(ctx: BuildContext, name: String) =
|
|
ctx.workspace.resolve(scriptsDir).resolve(name).toFile()
|
|
|
|
private fun deleteWorkspace(ctx: BuildContext) {
|
|
ctx.workspace.toFile().deleteRecursively()
|
|
}
|
|
|
|
private fun assertEmptyWorkspace(config: BuildContext) {
|
|
val workspace = config.workspace.toFile()
|
|
|
|
if (!workspace.exists()) {
|
|
workspace.mkdirs()
|
|
}
|
|
|
|
val wsList = workspace.list()
|
|
if (wsList != null && wsList.isNotEmpty()) {
|
|
throw WorkspaceIsNotEmpty(config.workspace.toString())
|
|
}
|
|
}
|
|
|
|
val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
|
|
|
}
|
|
|
|
data class BuildContext(
|
|
val config: BuildConfig,
|
|
val wsId: String,
|
|
val logFile: LogFile,
|
|
val rev: String,
|
|
val buildId: BuildId
|
|
) {
|
|
val workspace: Path = Paths.get(config.workspace, wsId)
|
|
}
|
|
|
|
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"
|
|
}
|