mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
feat(partnerctl-init): add safe Partner Home selection with overwrite/cancel flow
This commit is contained in:
@@ -52,8 +52,67 @@ class InitCommand : Runnable {
|
||||
}
|
||||
|
||||
private fun initHome(prompt: Prompt) {
|
||||
prompt.section("Initialize Partner Home")
|
||||
|
||||
fun resolveDefaultHome(): Path {
|
||||
home = choosePartnerHome(prompt)
|
||||
|
||||
Files.createDirectories(home)
|
||||
Files.createDirectories(home.resolve("resource"))
|
||||
Files.createDirectories(home.resolve("config"))
|
||||
|
||||
prompt.success("Partner Home initialized at $home")
|
||||
}
|
||||
|
||||
private fun choosePartnerHome(prompt: Prompt): Path {
|
||||
val defaultHome = resolveDefaultHome()
|
||||
|
||||
while (true) {
|
||||
val selectedHome = prompt.askPath(
|
||||
label = "Partner Home",
|
||||
defaultValue = defaultHome,
|
||||
required = true,
|
||||
directoryOnly = true,
|
||||
)
|
||||
|
||||
if (!hasHomeContent(selectedHome)) {
|
||||
return selectedHome
|
||||
}
|
||||
|
||||
prompt.warn("Partner Home already contains files: $selectedHome")
|
||||
|
||||
when (prompt.select(
|
||||
label = "Partner Home already contains files. Choose how to continue",
|
||||
choices = listOf(
|
||||
Choice(
|
||||
"Use another Partner Home",
|
||||
HomeDuplicateChoice.ANOTHER,
|
||||
"Choose a different directory",
|
||||
),
|
||||
Choice(
|
||||
"Overwrite current Partner Home",
|
||||
HomeDuplicateChoice.OVERWRITE,
|
||||
"Delete existing contents and continue",
|
||||
),
|
||||
Choice("Cancel init", HomeDuplicateChoice.EXIT),
|
||||
),
|
||||
defaultIndex = 0,
|
||||
)) {
|
||||
HomeDuplicateChoice.ANOTHER -> continue
|
||||
HomeDuplicateChoice.OVERWRITE -> {
|
||||
validateSafeHomeOverwrite(selectedHome)
|
||||
if (!prompt.confirm("Delete all files under $selectedHome?", false)) {
|
||||
continue
|
||||
}
|
||||
clearHomeDirectory(selectedHome)
|
||||
return selectedHome
|
||||
}
|
||||
|
||||
HomeDuplicateChoice.EXIT -> throw PromptCancelledException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDefaultHome(): Path {
|
||||
val envHome = System.getenv("PARTNER_HOME")?.trim()
|
||||
return if (!envHome.isNullOrEmpty()) {
|
||||
Paths.get(envHome).toAbsolutePath().normalize()
|
||||
@@ -62,21 +121,45 @@ class InitCommand : Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
prompt.section("Initialize Partner Home")
|
||||
private fun hasHomeContent(path: Path): Boolean {
|
||||
if (!Files.exists(path)) return false
|
||||
if (Files.isRegularFile(path)) return true
|
||||
if (!Files.isDirectory(path)) return false
|
||||
|
||||
val defaultHome = resolveDefaultHome()
|
||||
return Files.walk(path).use { stream ->
|
||||
stream.anyMatch { Files.isRegularFile(it) }
|
||||
}
|
||||
}
|
||||
|
||||
home = prompt.askPath(
|
||||
label = "Partner Home",
|
||||
defaultValue = defaultHome,
|
||||
required = true,
|
||||
directoryOnly = true,
|
||||
)
|
||||
Files.createDirectories(home)
|
||||
Files.createDirectories(home.resolve("resource"))
|
||||
Files.createDirectories(home.resolve("config"))
|
||||
private fun clearHomeDirectory(path: Path) {
|
||||
if (!Files.exists(path)) return
|
||||
if (!Files.isDirectory(path)) {
|
||||
throw CommandInterrupted("Partner Home is not a directory: $path")
|
||||
}
|
||||
|
||||
prompt.success("Partner Home initialized at $home")
|
||||
Files.walk(path).use { stream ->
|
||||
stream
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.filter { it != path }
|
||||
.forEach { Files.deleteIfExists(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateSafeHomeOverwrite(path: Path) {
|
||||
val normalized = path.toAbsolutePath().normalize()
|
||||
val userHome = Paths.get(System.getProperty("user.home")).toAbsolutePath().normalize()
|
||||
|
||||
if (normalized == normalized.root) {
|
||||
throw CommandInterrupted("Refuse to overwrite filesystem root: $normalized")
|
||||
}
|
||||
|
||||
if (normalized == userHome) {
|
||||
throw CommandInterrupted("Refuse to overwrite user home directory: $normalized")
|
||||
}
|
||||
|
||||
if (normalized.nameCount < 2) {
|
||||
throw CommandInterrupted("Refuse to overwrite suspiciously broad directory: $normalized")
|
||||
}
|
||||
}
|
||||
|
||||
private fun installPartner(prompt: Prompt) {
|
||||
@@ -266,4 +349,10 @@ class InitCommand : Runnable {
|
||||
SKIP("Skip")
|
||||
}
|
||||
|
||||
private enum class HomeDuplicateChoice {
|
||||
ANOTHER,
|
||||
OVERWRITE,
|
||||
EXIT
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user