mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: supports importing hosts from FinalShell (#295)
This commit is contained in:
@@ -16,6 +16,7 @@ import org.apache.commons.csv.CSVParser
|
||||
import org.apache.commons.csv.CSVPrinter
|
||||
import org.apache.commons.io.FileUtils
|
||||
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.ini4j.Ini
|
||||
@@ -365,6 +366,7 @@ class NewHostTree : JXTree() {
|
||||
val importMenu = JMenu(I18n.getString("termora.welcome.contextmenu.import"))
|
||||
val csvMenu = importMenu.add("CSV")
|
||||
val xShellMenu = importMenu.add("Xshell")
|
||||
val finalShellMenu = importMenu.add("FinalShell")
|
||||
val windTermMenu = importMenu.add("WindTerm")
|
||||
val secureCRTMenu = importMenu.add("SecureCRT")
|
||||
val mobaXtermMenu = importMenu.add("MobaXterm")
|
||||
@@ -398,6 +400,7 @@ class NewHostTree : JXTree() {
|
||||
xShellMenu.addActionListener { importHosts(lastNode, ImportType.Xshell) }
|
||||
secureCRTMenu.addActionListener { importHosts(lastNode, ImportType.SecureCRT) }
|
||||
mobaXtermMenu.addActionListener { importHosts(lastNode, ImportType.MobaXterm) }
|
||||
finalShellMenu.addActionListener { importHosts(lastNode, ImportType.FinalShell) }
|
||||
csvMenu.addActionListener { importHosts(lastNode, ImportType.CSV) }
|
||||
windTermMenu.addActionListener { importHosts(lastNode, ImportType.WindTerm) }
|
||||
open.addActionListener { openHosts(it, false) }
|
||||
@@ -656,6 +659,11 @@ class NewHostTree : JXTree() {
|
||||
chooser.dialogTitle = "Xshell Sessions"
|
||||
chooser.isAcceptAllFileFilterUsed = true
|
||||
}
|
||||
|
||||
ImportType.FinalShell -> {
|
||||
chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
|
||||
chooser.isAcceptAllFileFilterUsed = true
|
||||
}
|
||||
}
|
||||
|
||||
val dir = properties.getString("NewHostTree.ImportHosts.defaultDir", StringUtils.EMPTY)
|
||||
@@ -706,20 +714,22 @@ class NewHostTree : JXTree() {
|
||||
// 选择文件
|
||||
val code = chooser.showOpenDialog(owner)
|
||||
|
||||
// 记住目录
|
||||
properties.putString("NewHostTree.ImportHosts.defaultDir", chooser.currentDirectory.absolutePath)
|
||||
|
||||
if (code != JFileChooser.APPROVE_OPTION) {
|
||||
return
|
||||
}
|
||||
|
||||
val file = chooser.selectedFile
|
||||
properties.putString(
|
||||
"NewHostTree.ImportHosts.defaultDir",
|
||||
(if (FileUtils.isDirectory(file)) file else file.parentFile).absolutePath
|
||||
)
|
||||
|
||||
val nodes = when (type) {
|
||||
ImportType.WindTerm -> parseFromWindTerm(folder, file)
|
||||
ImportType.SecureCRT -> parseFromSecureCRT(folder, file)
|
||||
ImportType.MobaXterm -> parseFromMobaXterm(folder, file)
|
||||
ImportType.Xshell -> parseFromXshell(folder, file)
|
||||
ImportType.FinalShell -> parseFromFinalShell(folder, file)
|
||||
ImportType.CSV -> file.bufferedReader().use { parseFromCSV(folder, it) }
|
||||
}
|
||||
|
||||
@@ -874,6 +884,45 @@ class NewHostTree : JXTree() {
|
||||
return parseFromCSV(folder, StringReader(sw.toString()))
|
||||
}
|
||||
|
||||
private fun parseFromFinalShell(folder: HostTreeNode, dir: File): List<HostTreeNode> {
|
||||
val files = FileUtils.listFiles(
|
||||
dir,
|
||||
FileFilterUtils.suffixFileFilter("_connect_config.json"),
|
||||
FileFilterUtils.trueFileFilter()
|
||||
)
|
||||
|
||||
if (files.isEmpty()) {
|
||||
OptionPane.showMessageDialog(
|
||||
owner,
|
||||
I18n.getString("termora.welcome.contextmenu.import.finalshell-folder-empty")
|
||||
)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val sw = StringWriter()
|
||||
CSVPrinter(sw, CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).get()).use { printer ->
|
||||
for (file in files) {
|
||||
try {
|
||||
val json = ohMyJson.runCatching { ohMyJson.parseToJsonElement(file.readText()) }
|
||||
.getOrNull()?.jsonObject ?: continue
|
||||
val username = json["user_name"]?.jsonPrimitive?.content ?: StringUtils.EMPTY
|
||||
val label = json["name"]?.jsonPrimitive?.content ?: StringUtils.EMPTY
|
||||
val host = json["host"]?.jsonPrimitive?.content ?: StringUtils.EMPTY
|
||||
val port = json["port"]?.jsonPrimitive?.intOrNull ?: 22
|
||||
if (StringUtils.isAllBlank(host, label)) continue
|
||||
val folders = FilenameUtils.separatorsToUnix(file.parentFile.relativeTo(dir).toString())
|
||||
printer.printRecord(folders, StringUtils.defaultIfBlank(label, host), host, port, username, "SSH")
|
||||
} catch (e: Exception) {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(file.absolutePath, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parseFromCSV(folder, StringReader(sw.toString()))
|
||||
}
|
||||
|
||||
private fun parseFromCSV(folderNode: HostTreeNode, sr: Reader): List<HostTreeNode> {
|
||||
val records = CSVParser.builder()
|
||||
.setFormat(CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).setSkipHeaderRecord(true).get())
|
||||
@@ -954,7 +1003,8 @@ class NewHostTree : JXTree() {
|
||||
CSV,
|
||||
Xshell,
|
||||
SecureCRT,
|
||||
MobaXterm
|
||||
MobaXterm,
|
||||
FinalShell,
|
||||
}
|
||||
|
||||
private class MoveHostTransferable(val nodes: List<HostTreeNode>) : Transferable {
|
||||
|
||||
@@ -149,6 +149,7 @@ termora.welcome.contextmenu.import.csv.download-template=Do you want to import o
|
||||
termora.welcome.contextmenu.import.csv.download-template-done=Download the template successfully
|
||||
termora.welcome.contextmenu.import.csv.download-template-done-open-folder=Download the template successfully, Do you want to open the folder?
|
||||
termora.welcome.contextmenu.import.xshell-folder-empty=The folder does not contain any *.xsh files, Please select the correct Xshell Sessions directory
|
||||
termora.welcome.contextmenu.import.finalshell-folder-empty=The folder does not contain any *_connect_config.json files, Please select the correct FinalShell directory
|
||||
|
||||
# New Host
|
||||
termora.new-host.title=Create a new host
|
||||
|
||||
@@ -137,6 +137,7 @@ termora.welcome.contextmenu.import.csv.download-template=您要导入还是下
|
||||
termora.welcome.contextmenu.import.csv.download-template-done=下载成功
|
||||
termora.welcome.contextmenu.import.csv.download-template-done-open-folder=下载成功, 是否需要打开所在文件夹?
|
||||
termora.welcome.contextmenu.import.xshell-folder-empty=该文件夹不包含 *.xsh 文件,请选择正确的 Xshell 会话目录
|
||||
termora.welcome.contextmenu.import.finalshell-folder-empty=该文件夹不包含 *_connect_config.json 文件,请选择正确的 FinalShell 配置目录
|
||||
|
||||
# New Host
|
||||
termora.new-host.title=新建主机
|
||||
|
||||
@@ -135,6 +135,7 @@ termora.welcome.contextmenu.import.csv.download-template=您要匯入還是下
|
||||
termora.welcome.contextmenu.import.csv.download-template-done=下載成功
|
||||
termora.welcome.contextmenu.import.csv.download-template-done-open-folder=下載成功, 是否需要開啟所在資料夾?
|
||||
termora.welcome.contextmenu.import.xshell-folder-empty=該資料夾不包含 *.xsh 文件,請選擇正確的 Xshell 會話目錄
|
||||
termora.welcome.contextmenu.import.finalshell-folder-empty=該資料夾不包含 *_connect_config.json 文件,請選擇正確的 FinalShell 設定目錄
|
||||
|
||||
# New Host
|
||||
termora.new-host.title=新主機
|
||||
|
||||
Reference in New Issue
Block a user