mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
refactor(partnerctl-init): extract source build/install flow into reusable support helper
This commit is contained in:
@@ -1,100 +1,42 @@
|
||||
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.support.SourceBuildInstallSpec
|
||||
import work.slhaf.partner.ctl.support.buildAndInstallFromSource
|
||||
import work.slhaf.partner.ctl.ui.Prompt
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.name
|
||||
|
||||
private const val PARTNER_REPO_URL = "https://gitea.slhaf.work/slhaf/Partner.git"
|
||||
|
||||
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()),
|
||||
buildAndInstallFromSource(
|
||||
home = home,
|
||||
prompt = prompt,
|
||||
spec = SourceBuildInstallSpec(
|
||||
displayName = "Partner runtime",
|
||||
repoUrl = PARTNER_REPO_URL,
|
||||
sourceDirName = "Partner",
|
||||
buildCommand = listOf("mvn", "-pl", "Partner-Core", "-am", "package", "-DskipTests=true"),
|
||||
artifactDirectory = Paths.get("Partner-Core", "target"),
|
||||
artifactSelector = ::findLargestJar,
|
||||
installRelativePath = Paths.get("resource", "partner-core.jar"),
|
||||
),
|
||||
)
|
||||
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() {
|
||||
private fun findLargestJar(directory: Path): Path? {
|
||||
if (!directory.isDirectory()) return null
|
||||
|
||||
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 ->
|
||||
return Files.list(directory).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") }
|
||||
.orElse(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package work.slhaf.partner.ctl.support
|
||||
|
||||
import work.slhaf.partner.ctl.ui.Prompt
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
data class SourceBuildInstallSpec(
|
||||
val displayName: String,
|
||||
val repoUrl: String,
|
||||
val sourceDirName: String,
|
||||
val buildCommand: List<String>,
|
||||
val artifactDirectory: Path,
|
||||
val artifactSelector: (Path) -> Path?,
|
||||
val installRelativePath: Path,
|
||||
)
|
||||
|
||||
fun buildAndInstallFromSource(
|
||||
home: Path,
|
||||
prompt: Prompt,
|
||||
spec: SourceBuildInstallSpec,
|
||||
) {
|
||||
require(spec.sourceDirName.isNotBlank()) { "sourceDirName must not be blank" }
|
||||
require(spec.buildCommand.isNotEmpty()) { "buildCommand must not be empty" }
|
||||
|
||||
checkTool()
|
||||
|
||||
val tempDir = Files.createTempDirectory("partnerctl-build-")
|
||||
val sourceDir = tempDir.resolve(spec.sourceDirName)
|
||||
val targetPath = home.resolve(spec.installRelativePath)
|
||||
|
||||
try {
|
||||
prompt.info("Cloning ${spec.displayName} source from ${spec.repoUrl}")
|
||||
val cloneExitCode = inheritCommand(
|
||||
command = listOf("git", "clone", "--depth", "1", spec.repoUrl, sourceDir.toString()),
|
||||
)
|
||||
if (cloneExitCode != 0) {
|
||||
throw CommandInterrupted("Failed to clone ${spec.displayName} source from ${spec.repoUrl}")
|
||||
}
|
||||
|
||||
prompt.info("Building ${spec.displayName}")
|
||||
val buildExitCode = inheritCommand(
|
||||
command = spec.buildCommand,
|
||||
workingDirectory = sourceDir,
|
||||
)
|
||||
if (buildExitCode != 0) {
|
||||
throw CommandInterrupted("Failed to build ${spec.displayName}.")
|
||||
}
|
||||
|
||||
val artifactDir = sourceDir.resolve(spec.artifactDirectory)
|
||||
val artifact = spec.artifactSelector(artifactDir)
|
||||
?: throw CommandInterrupted("Could not find built ${spec.displayName} artifact in $artifactDir")
|
||||
|
||||
Files.createDirectories(targetPath.parent)
|
||||
Files.copy(artifact, targetPath, StandardCopyOption.REPLACE_EXISTING)
|
||||
prompt.success("${spec.displayName} installed at $targetPath")
|
||||
} finally {
|
||||
runCatching { 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. 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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user