feat(partnerctl-init): add source build install choice

This commit is contained in:
2026-05-03 21:06:46 +08:00
parent 7fcdb1c671
commit 6c74de2126
2 changed files with 117 additions and 1 deletions

View File

@@ -1,6 +1,8 @@
package work.slhaf.partner.ctl.commands package work.slhaf.partner.ctl.commands
import picocli.CommandLine import picocli.CommandLine
import work.slhaf.partner.ctl.commands.init.buildFromSource
import work.slhaf.partner.ctl.ui.Choice
import work.slhaf.partner.ctl.ui.Prompt import work.slhaf.partner.ctl.ui.Prompt
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
@@ -67,7 +69,18 @@ class InitCommand : Runnable {
} }
private fun installPartner(prompt: Prompt) { private fun installPartner(prompt: Prompt) {
TODO("Not yet implemented")
prompt.section("Install Partner")
val installChoice = prompt.select(
label = "Choose a installation method",
choices = listOf(Choice("Build Partner from source", InstallChoice.BUILD_FROM_SOURCE))
)
when (installChoice) {
InstallChoice.BUILD_FROM_SOURCE -> buildFromSource(home, prompt)
}
} }
private fun configureGateway(prompt: Prompt) { private fun configureGateway(prompt: Prompt) {
@@ -82,4 +95,7 @@ class InitCommand : Runnable {
TODO("Not yet implemented") TODO("Not yet implemented")
} }
private enum class InstallChoice {
BUILD_FROM_SOURCE
}
} }

View File

@@ -0,0 +1,100 @@
package work.slhaf.partner.ctl.commands.init
import work.slhaf.partner.ctl.support.CommandInterrupted
import work.slhaf.partner.ctl.support.inheritCommand
import work.slhaf.partner.ctl.support.runCommand
import work.slhaf.partner.ctl.ui.Prompt
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import kotlin.io.path.isDirectory
import kotlin.io.path.name
fun buildFromSource(home: Path, prompt: Prompt) {
checkTool()
val tempDir = Files.createTempDirectory("partnerctl-build-")
val sourceDir = tempDir.resolve("Partner")
val repoUrl = "https://gitea.slhaf.work/slhaf/Partner.git"
val targetJar = home.resolve("resource").resolve("partner-core.jar")
try {
prompt.info("Cloning Partner source from $repoUrl")
val cloneExitCode = inheritCommand(
command = listOf("git", "clone", "--depth", "1", repoUrl, sourceDir.toString()),
)
if (cloneExitCode != 0) {
throw CommandInterrupted("Failed to clone Partner source from $repoUrl")
}
prompt.info("Building Partner-Core and required modules")
val buildExitCode = inheritCommand(
command = listOf("mvn", "-pl", "Partner-Core", "-am", "package", "-DskipTests=true"),
workingDirectory = sourceDir,
)
if (buildExitCode != 0) {
throw CommandInterrupted("Failed to build Partner runtime. Please make sure Maven is using JDK 21.")
}
val builtJar = findPartnerCoreJar(sourceDir)
Files.createDirectories(targetJar.parent)
Files.copy(builtJar, targetJar, StandardCopyOption.REPLACE_EXISTING)
prompt.success("Partner runtime installed at $targetJar")
} finally {
tempDir.toFile().deleteRecursively()
}
}
private fun checkTool() {
fun buildToolLackedMessage(lack: Map<String, String>): String {
return buildString {
appendLine("Missing required build tools:")
appendLine()
lack.forEach { (tool, reason) ->
appendLine("$tool:")
appendLine(" $reason")
}
appendLine()
appendLine("Install the missing tools, then rerun:")
appendLine(" partnerctl init")
}.trimEnd()
}
val lack = mutableMapOf<String, String>()
if (runCommand(listOf("java", "--version")).exitCode != 0) {
lack["java"] = "Required to run Maven and Partner runtime. Command failed: java --version"
}
if (runCommand(listOf("javac", "--version")).exitCode != 0) {
lack["javac"] =
"Required to compile Partner from source. Install a JDK, not just a JRE. Command failed: javac --version"
}
if (runCommand(listOf("git", "--version")).exitCode != 0) {
lack["git"] = "Required to clone Partner source. Command failed: git --version"
}
if (runCommand(listOf("mvn", "--version")).exitCode != 0) {
lack["mvn"] = "Required to build Partner from source. Command failed: mvn --version"
}
if (lack.isNotEmpty()) {
throw CommandInterrupted(buildToolLackedMessage(lack))
}
}
private fun findPartnerCoreJar(sourceDir: Path): Path {
val targetDir = sourceDir.resolve("Partner-Core").resolve("target")
if (!targetDir.isDirectory()) {
throw CommandInterrupted("Partner-Core target directory does not exist: $targetDir")
}
return Files.list(targetDir).use { stream ->
stream
.filter { it.name.endsWith(".jar") }
.filter { !it.name.startsWith("original-") }
.filter { !it.name.endsWith("-sources.jar") }
.filter { !it.name.endsWith("-javadoc.jar") }
.max(Comparator.comparingLong { Files.size(it) })
.orElseThrow { CommandInterrupted("Could not find built Partner Core jar in $targetDir") }
}
}