chore: improve rm -rf

This commit is contained in:
hstyi
2025-07-04 15:27:09 +08:00
committed by hstyi
parent 1c90fb4e18
commit 919c06779d
5 changed files with 88 additions and 50 deletions

View File

@@ -0,0 +1,34 @@
package app.termora.transfer
import org.apache.sshd.sftp.client.fs.SftpFileSystem
import org.apache.sshd.sftp.client.fs.SftpPath
import kotlin.math.max
class CommandTransfer(
parentId: String,
path: SftpPath,
isDirectory: Boolean,
private val size: Long,
val command: String,
) : AbstractTransfer(parentId, path, path, isDirectory) {
private var executed = false
override suspend fun transfer(bufferSize: Int): Long {
if (executed) return 0
val fs = source().fileSystem as SftpFileSystem
fs.session.executeRemoteCommand(command)
executed = true
return this.size()
}
override fun scanning(): Boolean {
return false
}
override fun size(): Long {
return max(size, 1)
}
}

View File

@@ -11,6 +11,7 @@ import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.time.DateFormatUtils import org.apache.commons.lang3.time.DateFormatUtils
import org.apache.sshd.sftp.client.fs.SftpPath
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.awt.Component import java.awt.Component
import java.awt.Dimension import java.awt.Dimension
@@ -31,6 +32,7 @@ import kotlin.collections.ArrayDeque
import kotlin.collections.List import kotlin.collections.List
import kotlin.collections.Set import kotlin.collections.Set
import kotlin.collections.isNotEmpty import kotlin.collections.isNotEmpty
import kotlin.io.path.absolutePathString
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.name import kotlin.io.path.name
import kotlin.io.path.pathString import kotlin.io.path.pathString
@@ -267,8 +269,8 @@ class DefaultInternalTransferManager(
val isDirectory = pair.second.isDirectory val isDirectory = pair.second.isDirectory
val path = pair.first val path = pair.first
if (isDirectory.not()) { if (isDirectory.not() || mode == TransferMode.Rmrf) {
val transfer = createTransfer(path, workdir.resolve(path.name), false, StringUtils.EMPTY, mode, action) val transfer = createTransfer(path, workdir.resolve(path.name), isDirectory, StringUtils.EMPTY, mode, action)
return if (transferManager.addTransfer(transfer)) FileVisitResult.CONTINUE else FileVisitResult.TERMINATE return if (transferManager.addTransfer(transfer)) FileVisitResult.CONTINUE else FileVisitResult.TERMINATE
} }
@@ -363,39 +365,49 @@ class DefaultInternalTransferManager(
action:TransferAction, action:TransferAction,
permissions: Set<PosixFilePermission>? = null permissions: Set<PosixFilePermission>? = null
): Transfer { ): Transfer {
if (mode == TransferMode.Delete) { when {
return DeleteTransfer( mode == TransferMode.Delete -> {
parentId, return DeleteTransfer(
source, parentId,
isDirectory, source,
if (isDirectory) 1 else Files.size(source) isDirectory,
) if (isDirectory) 1 else Files.size(source)
} else if (mode == TransferMode.ChangePermission) { )
if (permissions == null) throw IllegalStateException() }
return ChangePermissionTransfer( mode == TransferMode.Rmrf -> {
parentId, return CommandTransfer(
target, parentId,
isDirectory = isDirectory, source as SftpPath,
permissions = permissions, isDirectory,
size = if (isDirectory) 1 else Files.size(target) if (isDirectory) 1 else Files.size(source),
) "rm -rf ${source.absolutePathString()}",
} )
}
if (isDirectory) { mode == TransferMode.ChangePermission -> {
return DirectoryTransfer( if (permissions == null) throw IllegalStateException()
return ChangePermissionTransfer(
parentId,
target,
isDirectory = isDirectory,
permissions = permissions,
size = if (isDirectory) 1 else Files.size(target)
)
}
isDirectory -> {
return DirectoryTransfer(
parentId = parentId,
source = source,
target = target,
)
}
else -> return FileTransfer(
parentId = parentId, parentId = parentId,
source = source, source = source,
target = target, target = target,
action = action,
size = Files.size(source)
) )
} }
return FileTransfer(
parentId = parentId,
source = source,
target = target,
action = action,
size = Files.size(source)
)
} }

View File

@@ -9,6 +9,7 @@ interface InternalTransferManager {
Delete, Delete,
Transfer, Transfer,
ChangePermission, ChangePermission,
Rmrf,
} }
/** /**

View File

@@ -77,13 +77,15 @@ class TransferTreeTableNode(transfer: Transfer) : DefaultMutableTreeTableNode(tr
private fun formatPath(path: Path, target: Boolean): String { private fun formatPath(path: Path, target: Boolean): String {
if (target) { if (target) {
if (transfer is DeleteTransfer) { when (transfer) {
return I18n.getString("termora.transport.sftp.status.deleting") is DeleteTransfer -> return I18n.getString("termora.transport.sftp.status.deleting")
} else if (transfer is ChangePermissionTransfer) { is CommandTransfer -> return (transfer as CommandTransfer).command
val permissions = (transfer as ChangePermissionTransfer).permissions is ChangePermissionTransfer -> {
// @formatter:off val permissions = (transfer as ChangePermissionTransfer).permissions
return "${I18n.getString("termora.transport.table.permissions")} -> ${PosixFilePermissions.toString(permissions)}" // @formatter:off
// @formatter:on return "${I18n.getString("termora.transport.table.permissions")} -> ${PosixFilePermissions.toString(permissions)}"
// @formatter:on
}
} }
} }
@@ -95,7 +97,7 @@ class TransferTreeTableNode(transfer: Transfer) : DefaultMutableTreeTableNode(tr
} }
private fun formatStatus(state: State): String { private fun formatStatus(state: State): String {
if (transfer is DeleteTransfer && state == State.Processing) { if ((transfer is DeleteTransfer || transfer is CommandTransfer) && state == State.Processing) {
return I18n.getString("termora.transport.sftp.status.deleting") return I18n.getString("termora.transport.sftp.status.deleting")
} }

View File

@@ -18,7 +18,6 @@ import org.apache.commons.lang3.ArrayUtils
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.commons.lang3.time.DateFormatUtils import org.apache.commons.lang3.time.DateFormatUtils
import org.apache.sshd.sftp.client.fs.SftpFileSystem
import org.apache.sshd.sftp.client.fs.WithFileAttributes import org.apache.sshd.sftp.client.fs.WithFileAttributes
import org.jdesktop.swingx.JXBusyLabel import org.jdesktop.swingx.JXBusyLabel
import org.jdesktop.swingx.JXPanel import org.jdesktop.swingx.JXPanel
@@ -34,7 +33,6 @@ import java.awt.event.*
import java.beans.PropertyChangeEvent import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener import java.beans.PropertyChangeListener
import java.io.File import java.io.File
import java.io.OutputStream
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Files import java.nio.file.Files
@@ -1023,16 +1021,7 @@ class TransportPanel(
val target = source.parent.resolve(e.source.toString()) val target = source.parent.resolve(e.source.toString())
processPath(e.source.toString()) { source.moveTo(target) } processPath(e.source.toString()) { source.moveTo(target) }
} else if (actionCommand == TransportPopupMenu.ActionCommand.Rmrf) { } else if (actionCommand == TransportPopupMenu.ActionCommand.Rmrf) {
processPath(StringUtils.EMPTY) { transferManager.addTransfer(files, InternalTransferManager.TransferMode.Rmrf)
val session = (_fileSystem as SftpFileSystem).clientSession
for (path in files.map { it.first }) {
session.executeRemoteCommand(
"rm -rf '${path.absolutePathString()}'",
OutputStream.nullOutputStream(),
Charsets.UTF_8
)
}
}
} else if (actionCommand == TransportPopupMenu.ActionCommand.ChangePermissions) { } else if (actionCommand == TransportPopupMenu.ActionCommand.ChangePermissions) {
val c = e.source as TransportPopupMenu.ChangePermission val c = e.source as TransportPopupMenu.ChangePermission
val path = files.first().first val path = files.first().first