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,14 +365,25 @@ class DefaultInternalTransferManager(
action:TransferAction, action:TransferAction,
permissions: Set<PosixFilePermission>? = null permissions: Set<PosixFilePermission>? = null
): Transfer { ): Transfer {
if (mode == TransferMode.Delete) { when {
mode == TransferMode.Delete -> {
return DeleteTransfer( return DeleteTransfer(
parentId, parentId,
source, source,
isDirectory, isDirectory,
if (isDirectory) 1 else Files.size(source) if (isDirectory) 1 else Files.size(source)
) )
} else if (mode == TransferMode.ChangePermission) { }
mode == TransferMode.Rmrf -> {
return CommandTransfer(
parentId,
source as SftpPath,
isDirectory,
if (isDirectory) 1 else Files.size(source),
"rm -rf ${source.absolutePathString()}",
)
}
mode == TransferMode.ChangePermission -> {
if (permissions == null) throw IllegalStateException() if (permissions == null) throw IllegalStateException()
return ChangePermissionTransfer( return ChangePermissionTransfer(
parentId, parentId,
@@ -380,16 +393,14 @@ class DefaultInternalTransferManager(
size = if (isDirectory) 1 else Files.size(target) size = if (isDirectory) 1 else Files.size(target)
) )
} }
isDirectory -> {
if (isDirectory) {
return DirectoryTransfer( return DirectoryTransfer(
parentId = parentId, parentId = parentId,
source = source, source = source,
target = target, target = target,
) )
} }
else -> return FileTransfer(
return FileTransfer(
parentId = parentId, parentId = parentId,
source = source, source = source,
target = target, target = target,
@@ -397,6 +408,7 @@ class DefaultInternalTransferManager(
size = Files.size(source) size = Files.size(source)
) )
} }
}
} }

View File

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

View File

@@ -77,15 +77,17 @@ 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
is ChangePermissionTransfer -> {
val permissions = (transfer as ChangePermissionTransfer).permissions val permissions = (transfer as ChangePermissionTransfer).permissions
// @formatter:off // @formatter:off
return "${I18n.getString("termora.transport.table.permissions")} -> ${PosixFilePermissions.toString(permissions)}" return "${I18n.getString("termora.transport.table.permissions")} -> ${PosixFilePermissions.toString(permissions)}"
// @formatter:on // @formatter:on
} }
} }
}
if (path.fileSystem == FileSystems.getDefault()) { if (path.fileSystem == FileSystems.getDefault()) {
return path.absolutePathString() return path.absolutePathString()
@@ -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