mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-15 18:02:58 +08:00
feat: supports importing hosts from SSH config (#359)
This commit is contained in:
@@ -14,6 +14,7 @@ import org.apache.commons.io.FilenameUtils
|
||||
import org.apache.commons.io.filefilter.FileFilterUtils
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
||||
import org.apache.sshd.client.config.hosts.HostConfigEntry
|
||||
import org.ini4j.Ini
|
||||
import org.ini4j.Reg
|
||||
import org.jdesktop.swingx.action.ActionManager
|
||||
@@ -185,8 +186,10 @@ class NewHostTree : SimpleTree() {
|
||||
val finalShellMenu = importMenu.add("FinalShell")
|
||||
val windTermMenu = importMenu.add("WindTerm")
|
||||
val secureCRTMenu = importMenu.add("SecureCRT")
|
||||
val sshMenu = importMenu.add(".ssh/config")
|
||||
val mobaXtermMenu = importMenu.add("MobaXterm")
|
||||
|
||||
|
||||
val open = popupMenu.add(I18n.getString("termora.welcome.contextmenu.connect"))
|
||||
val openWith = popupMenu.add(JMenu(I18n.getString("termora.welcome.contextmenu.connect-with"))) as JMenu
|
||||
val openWithSFTP = openWith.add("SFTP")
|
||||
@@ -218,6 +221,7 @@ class NewHostTree : SimpleTree() {
|
||||
secureCRTMenu.addActionListener { importHosts(lastNode, ImportType.SecureCRT) }
|
||||
electermMenu.addActionListener { importHosts(lastNode, ImportType.electerm) }
|
||||
mobaXtermMenu.addActionListener { importHosts(lastNode, ImportType.MobaXterm) }
|
||||
sshMenu.addActionListener { importHosts(lastNode, ImportType.SSH) }
|
||||
finalShellMenu.addActionListener { importHosts(lastNode, ImportType.FinalShell) }
|
||||
csvMenu.addActionListener { importHosts(lastNode, ImportType.CSV) }
|
||||
windTermMenu.addActionListener { importHosts(lastNode, ImportType.WindTerm) }
|
||||
@@ -428,6 +432,7 @@ class NewHostTree : SimpleTree() {
|
||||
|
||||
when (type) {
|
||||
ImportType.WindTerm -> chooser.fileFilter = FileNameExtensionFilter("WindTerm (*.sessions)", "sessions")
|
||||
ImportType.SSH -> chooser.fileFilter = FileNameExtensionFilter("SSH (config)", "config")
|
||||
ImportType.CSV -> chooser.fileFilter = FileNameExtensionFilter("CSV (*.csv)", "csv")
|
||||
ImportType.SecureCRT -> chooser.fileFilter = FileNameExtensionFilter("SecureCRT (*.xml)", "xml")
|
||||
ImportType.electerm -> chooser.fileFilter = FileNameExtensionFilter("electerm (*.json)", "json")
|
||||
@@ -493,19 +498,23 @@ class NewHostTree : SimpleTree() {
|
||||
}
|
||||
|
||||
// 选择文件
|
||||
val code = chooser.showOpenDialog(owner)
|
||||
|
||||
if (code != JFileChooser.APPROVE_OPTION) {
|
||||
return
|
||||
if (type != ImportType.SSH) {
|
||||
val code = chooser.showOpenDialog(owner)
|
||||
if (code != JFileChooser.APPROVE_OPTION) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val file = chooser.selectedFile
|
||||
properties.putString(
|
||||
"NewHostTree.ImportHosts.defaultDir",
|
||||
(if (FileUtils.isDirectory(file)) file else file.parentFile).absolutePath
|
||||
)
|
||||
if (file != null && file.parentFile != null) {
|
||||
properties.putString(
|
||||
"NewHostTree.ImportHosts.defaultDir",
|
||||
(if (FileUtils.isDirectory(file)) file else file.parentFile).absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
val nodes = when (type) {
|
||||
ImportType.SSH -> parseFromSSH(folder)
|
||||
ImportType.WindTerm -> parseFromWindTerm(folder, file)
|
||||
ImportType.SecureCRT -> parseFromSecureCRT(folder, file)
|
||||
ImportType.MobaXterm -> parseFromMobaXterm(folder, file)
|
||||
@@ -537,6 +546,9 @@ class NewHostTree : SimpleTree() {
|
||||
|
||||
// 重新加载
|
||||
model.reload(folder)
|
||||
|
||||
// expand root
|
||||
expandPath(TreePath(model.getPathToRoot(folder)))
|
||||
}
|
||||
|
||||
private fun parseFromWindTerm(folder: HostTreeNode, file: File): List<HostTreeNode> {
|
||||
@@ -562,6 +574,26 @@ class NewHostTree : SimpleTree() {
|
||||
return parseFromCSV(folder, StringReader(sw.toString()))
|
||||
}
|
||||
|
||||
private fun parseFromSSH(folder: HostTreeNode): List<HostTreeNode> {
|
||||
val entries = HostConfigEntry.readHostConfigEntries(HostConfigEntry.getDefaultHostConfigFile())
|
||||
|
||||
val sw = StringWriter()
|
||||
CSVPrinter(sw, CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).get()).use { printer ->
|
||||
for (entry in entries) {
|
||||
printer.printRecord(
|
||||
StringUtils.EMPTY,
|
||||
StringUtils.defaultString(entry.host),
|
||||
StringUtils.defaultString(entry.hostName),
|
||||
if (entry.port == 0) 22 else entry.port,
|
||||
StringUtils.defaultString(entry.username),
|
||||
"SSH"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return parseFromCSV(folder, StringReader(sw.toString()))
|
||||
}
|
||||
|
||||
private fun parseFromSecureCRT(folder: HostTreeNode, file: File): List<HostTreeNode> {
|
||||
val xPath = XPathFactory.newInstance().newXPath()
|
||||
val db = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
@@ -861,6 +893,7 @@ class NewHostTree : SimpleTree() {
|
||||
PuTTY,
|
||||
SecureCRT,
|
||||
MobaXterm,
|
||||
SSH,
|
||||
FinalShell,
|
||||
electerm,
|
||||
}
|
||||
|
||||
14
src/test/kotlin/app/termora/HostConfigEntryTest.kt
Normal file
14
src/test/kotlin/app/termora/HostConfigEntryTest.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package app.termora
|
||||
|
||||
import org.apache.sshd.client.config.hosts.HostConfigEntry
|
||||
import kotlin.test.Test
|
||||
|
||||
class HostConfigEntryTest {
|
||||
@Test
|
||||
fun test() {
|
||||
val entries = HostConfigEntry.readHostConfigEntries(HostConfigEntry.getDefaultHostConfigFile())
|
||||
for (entry in entries) {
|
||||
println(entry.host)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user