升级工具1

发布于:2024-10-11 ⋅ 阅读:(187) ⋅ 点赞:(0)
import sys
import ftplib
import shutil

from datetime import datetime

from PySide6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
    QLineEdit, QPushButton, QProgressBar, QMessageBox, QFrame, QFileDialog, QComboBox, QPlainTextEdit, QDialog,
)
from db import Sqlite3Database
from PySide6.QtGui import QIcon, QFont
from PySide6.QtCore import QThread, Signal, Qt, QTimer, QPropertyAnimation, QRect
import os

def ftp_mkdir_recursive(ftp: ftplib.FTP, remote_directory: str):
    """
    递归创建远程 FTP 目录,如果不存在则创建
    :param ftp: FTP 对象
    :param remote_directory: 远程目录路径
    """
    dirs = remote_directory.split('/')
    current_path = ''
    for directory in dirs:
        if directory not in ["",".","./"]:  # 跳过空字符串
            current_path += '/' + directory
            try:
                ftp.cwd(current_path)  # 尝试切换到该目录
            except ftplib.error_perm:
                ftp.mkd(current_path)
                ftp.cwd(current_path)  # 切换到刚创建的目录

def ftp_upload_recursive(ftp: ftplib.FTP, local_dir: str, remote_dir: str):
    """
    递归上传本地目录到 FTP 服务器,并创建不存在的远程目录
    :param ftp: FTP 对象
    :param local_dir: 本地目录路径
    :param remote_dir: 远程 FTP 目录路径
    """
    ftp_mkdir_recursive(ftp, remote_dir)
    for root, dirs, files in os.walk(local_dir):
        rel_path = os.path.relpath(root, local_dir)
        rel_remote_path = os.path.join(remote_dir, rel_path).replace('\\', '/')
        for dir_name in dirs:
            ftp_mkdir_recursive(ftp, f"{rel_remote_path}/{dir_name}")
        for file_name in files:
            local_file_path = os.path.join(root, file_name)
            remote_file_path = f"{rel_remote_path}/{file_name}".replace('\\', '/')
            with open(local_file_path, 'rb') as file:
                print(f"Uploading {local_file_path} to {remote_file_path}")
                ftp.storbinary(f'STOR {remote_file_path}', file)

def ftp_directory_exists(ftp: ftplib.FTP, directory: str) -> bool:
    """
    检查 FTP 服务器上的目录是否存在
    :param ftp: FTP 对象
    :param directory: 需要检查的目录路径
    :return: 如果目录存在则返回 True,否则返回 False
    """
    current_dir = ftp.pwd()  # 记住当前所在目录
    try:
        ftp.cwd(directory)  # 尝试切换到目标目录
        ftp.cwd(current_dir)  # 成功后返回原始目录
        return True
    except ftplib.error_perm as e:
        if str(e).startswith('550'):
            print(f"Error:{e}")
            return False
        else:
            raise e  # 如果是其他错误,抛出异常

class LogWindow(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Upgrade Progress")
        self.resize(500, 350)

        # 设置样式表美化界面
        self.setStyleSheet("""
            QDialog {
                background-color: #f2f2f2;
                border-radius: 10px;
            }
            QPlainTextEdit {
                background-color: #1e1e1e;
                color: #dcdcdc;
                border-radius: 5px;
                padding: 10px;
                font-family: Consolas, monospace;
                font-size: 14px;
            }
            QPushButton {
                background-color: #4caf50;
                color: white;
                border-radius: 5px;
                padding: 8px 15px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
        """)

        # 布局
        main_layout = QVBoxLayout()

        # 添加日志显示窗口
        self.log_edit = QPlainTextEdit(self)
        self.log_edit.setReadOnly(True)
        main_layout.addWidget(self.log_edit)

        # 底部的关闭按钮
        self.close_button = QPushButton("Close", self)
        self.close_button.clicked.connect(self.close)

        # 添加按钮布局
        button_layout = QHBoxLayout()
        button_layout.addStretch(1)  # 左侧扩展
        button_layout.addWidget(self.close_button)  # 右侧关闭按钮
        main_layout.addLayout(button_layout)

        self.setLayout(main_layout)

    def clear(self):
        self.log_edit.clear()

    def append_log(self, text):
        self.log_edit.appendPlainText(text)
        self.log_edit.verticalScrollBar().setValue(self.log_edit.verticalScrollBar().maximum())

class FTPDownloadThread(QThread):
    progress = Signal(int)
    finished = Signal(bool)
    progressMsg = Signal(str)

    def __init__(self, host, username, password, file_path, save_path):
        super().__init__()
        self.host = host
        self.username = username
        self.password = password
        self.file_path = file_path
        self.save_path = save_path

    def run(self):
        try:
            ftp = ftplib.FTP(self.host)
            ftp.login(self.username, self.password)
            total_size = ftp.size(self.file_path)

            with open(self.save_path, 'wb') as f:
                def handle_block(block):
                    f.write(block)
                    self.progress.emit(int(f.tell() / total_size * 100))
                ftp.retrbinary(f"RETR {self.file_path}", handle_block)

            ftp.quit()
            self.finished.emit(True)
        except Exception as e:
            print(f"Error: {e}")
            self.finished.emit(False)


class FTPUploadThread(QThread):
    progress = Signal(int)
    finished = Signal(bool)
    progressMsg = Signal(str)

    def __init__(self, host: str, username: str, password: str, remotePath: str, save_path: str):
        super().__init__()
        self.host = host
        self.username = username
        self.password = password
        self.file_path = remotePath
        self.save_path = save_path

    def run(self):
        try:
            ftp = ftplib.FTP(self.host,timeout=3)
            ftp.login(self.username, self.password)
            current_dir = os.getcwd()
            os.chdir(self.save_path)
            self.progressMsg.emit("开始扫描升级文件夹")
            for check in ["/mnt/flash","/"]:
                if ftp_directory_exists(ftp, check):
                    self.progressMsg.emit("开始检查文件是否合法")
                    for dirpath, dirnames, filenames in os.walk("."):
                        for filename in filenames:
                            total_size = os.path.getsize(dirpath + "/" + filename)
                            tmp = dirpath
                            self.progress.emit(tmp)
                            if tmp != ".":
                                self.progressMsg.emit(f"开始创建合法目录:{tmp.replace('\\','/')}")
                                ftp_mkdir_recursive(ftp,f"{check}/{tmp}".replace("\\","/"))
                                self.progressMsg.emit(f"完成创建合法目录:{tmp.replace('\\','/')}")
                            self.progressMsg.emit(f"{dirpath + "/" + filename}")
                            if filename.find(".db") != -1:
                                self.progressMsg.emit(f"{dirpath}/{filename} 复写数据库开始")
                                try:
                                    with open(current_dir+"/"+filename, 'wb') as f:
                                        def handle_block(block):
                                            f.write(block)
                                        ftp.retrbinary(f"RETR {check}/config/{filename}", callback=handle_block)
                                    newDB = Sqlite3Database(dirpath + "/" + filename)
                                    oldDB = Sqlite3Database(filename)
                                    oldDB.patch_database("V0",6,"ID",0,newDB)
                                    self.progressMsg.emit(f"{dirpath}/{filename} 复写数据库完成")
                                    dbk =  filename + "." + datetime.now().strftime("%Y%m%d%H%M%S")
                                    self.progressMsg.emit(f"备份数据库名称: {dbk}")
                                    newDB.close()
                                    oldDB.close()
                                    shutil.copy(current_dir+"/"+filename,current_dir+"/"+dbk)
                                except ftplib.error_perm as e:
                                       self.progressMsg.emit(f"Error: {e}")
                            self.progressMsg.emit(f"开始上传:{dirpath}/{filename}")
                            with open(f"{dirpath + "/" + filename}", 'rb') as f:
                                track_length = 0
                                def _handle_block(block):
                                    nonlocal track_length
                                    track_length = track_length + len(block)
                                    self.progress.emit((track_length / total_size) * 100)
                                ftp.storbinary(f"STOR {check+"/"+tmp+"/"+filename}", f, callback=_handle_block)
                            self.progressMsg.emit(f"完成上传:{dirpath}/{filename}")
                    break
            os.chdir(current_dir)
            ftp.quit()
            self.finished.emit(True)
        except Exception as e:
            self.progressMsg.emit(f"Error: {e}")
            self.finished.emit(False)


def progress_bar_style():
    return """
        QProgressBar {
            border: 1px solid #007BFF;  /* 简单的边框 */
            border-radius: 0;  /* 去掉圆角 */
            text-align: center;
        }
        QProgressBar::chunk {
            background-color: #007BFF;  /* 进度条填充色 */
        }
    """


def button_style():
    return """
        QPushButton {
            background-color: #007BFF;  /* 按钮背景色 */
            color: white;  /* 按钮文字颜色 */
            font-size: 16px;
            padding: 8px;  /* 按钮内边距 */
            border: none;  /* 去掉边框 */
        }
        QPushButton:hover {
            background-color: #0056b3;  /* 鼠标悬停时的背景色 */
        }
    """


def input_style():
    return """
        QLineEdit {
            border: 1px solid gray;  /* 简单的边框 */
            border-radius: 0;  /* 去掉圆角 */
            padding: 5px;
            font-size: 14px;
        }
        QLineEdit:focus {
            border-color: #007BFF;  /* 聚焦时的边框颜色 */
        }
    """
def combobox_style():
    return """
            QComboBox {
                font-size: 14px;
                padding: 5px;
                border: 2px solid #007BFF;
                border-radius: 5px;
                background-color: white;
            }
            QComboBox QAbstractItemView {
                border: 1px solid #007BFF;
                background-color: #f9f9f9;
                selection-background-color: #007BFF;
                selection-color: white;
            }
            QComboBox::drop-down {
                subcontrol-origin: padding;
                subcontrol-position: top right;
                width: 30px;
                border-left-width: 1px;
                border-left-color: #007BFF;
                border-left-style: solid;
                border-top-right-radius: 5px;
                border-bottom-right-radius: 5px;
                background-color: #007BFF;
            }
        """

class FTPUpgradeWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.downloadThread = None
        self.upgrade_button = None
        self.progress_bar = None
        self.rollback_button = None
        self.browse_button = None
        self.file_input = None
        self.password_input = None
        self.user_input = None
        self.host_input = None
        self.uploadThread = None
        self.log_window = LogWindow()
        self.log_window.setWindowModality(Qt.WindowModality.NonModal)
        self.log_window.setMaximumSize(800,600)
        self.log_window.setMinimumSize(800,600)
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('FTP Upgrade')
        self.setWindowIcon(QIcon('ftp_icon.png'))

        layout = QVBoxLayout()

        frame = QFrame(self)
        frame.setFrameShape(QFrame.NoFrame)  # 不使用边框
        frame_layout = QVBoxLayout()

        self.host_input = QComboBox(self)
        self.host_input.addItems(["近端机 AU ftp://192.168.1.2", "远端机器 RU ftp://192.168.98.98","测试机器 ftp://localhost"])
        self.host_input.setPlaceholderText('Hostname (ftp://hostname)')
        self.host_input.setStyleSheet(combobox_style())
        self.host_input.setEditable(True)

        self.user_input = QLineEdit(self)
        self.user_input.setPlaceholderText('Username')
        self.user_input.setStyleSheet(input_style())

        self.user_input.setText("root")

        self.password_input = QLineEdit(self)
        self.password_input.setPlaceholderText('Password')
        self.password_input.setEchoMode(QLineEdit.Password)  # 隐藏密码输入
        self.password_input.setStyleSheet(input_style())

        self.password_input.setText("root")

        self.file_input = QLineEdit(self)
        self.file_input.setPlaceholderText('File Path (dir)')
        self.file_input.setStyleSheet(input_style())

        # 文件选择按钮
        self.browse_button = QPushButton('Browse...', self)
        self.browse_button.setStyleSheet(button_style())
        self.browse_button.clicked.connect(self.browse_file)

        self.progress_bar = QProgressBar(self)
        self.progress_bar.setValue(0)
        self.progress_bar.setStyleSheet(progress_bar_style())

        self.upgrade_button = QPushButton('Start Upgrade', self)
        self.upgrade_button.setStyleSheet(button_style())
        self.upgrade_button.clicked.connect(self.start_upgrade)

        self.rollback_button = QPushButton('Rollback', self)
        self.rollback_button.setStyleSheet(button_style())
        self.rollback_button.clicked.connect(self.rollback)
        self.rollback_button.setEnabled(False)  # 初始禁用

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.upgrade_button)
        button_layout.addWidget(self.rollback_button)

        frame_layout.addWidget(QLabel('Enter FTP Details:'))
        frame_layout.addWidget(self.host_input)
        frame_layout.addWidget(self.user_input)
        frame_layout.addWidget(self.password_input)
        frame_layout.addWidget(self.file_input)
        frame_layout.addWidget(self.browse_button)  # 添加浏览按钮
        frame_layout.addWidget(self.progress_bar)
        frame_layout.addLayout(button_layout)

        frame.setLayout(frame_layout)

        layout.addWidget(frame)
        self.setLayout(layout)
        self.setMaximumSize(400, 300)
        self.setMinimumSize(400, 300)
        font = QFont("Arial", 10)
        self.setFont(font)

    def browse_file(self):
        dirName = QFileDialog.getExistingDirectory(self, "Select Dir", "")
        if dirName:
            self.file_input.setText(dirName)  # 设置选择的文件路径

    def start_upgrade(self):
        try:
            host = self.host_input.currentText().strip().split('://')[1]
            username = self.user_input.text().strip()
            password = self.password_input.text().strip()
            file_path = self.file_input.text().strip()
        except Exception as e:
            QMessageBox.warning(self, 'Input Error', 'Please enter valid FTP details! {}'.format(e))
            return

        main_window_rect = self.geometry()
        log_window_x = main_window_rect.x() + main_window_rect.width() + 10  # 在主窗口右侧10像素
        log_window_y = main_window_rect.y()
        self.log_window.move(log_window_x, log_window_y)
        self.log_window.show()
        self.rollback_button.setEnabled(True)
        self.upgrade_button.setEnabled(False)
        self.uploadThread = FTPUploadThread(host, username, password, "/", file_path)  # 你可以选择保存路径
        self.uploadThread.progress.connect(self.progress_bar.setValue)
        self.uploadThread.finished.connect(self.on_upgrade_finished)
        self.uploadThread.progressMsg.connect(self.log)
        self.uploadThread.start()

    def log(self,msg:str):
        self.log_window.append_log(msg)

    def rollback(self):
        try:
            host = self.host_input.currentText().strip().split('://')[1]
            username = self.user_input.text().strip()
            password = self.password_input.text().strip()
            file_path = self.file_input.text().strip()
        except Exception as e:
            QMessageBox.warning(self, 'Input Error', 'Please enter valid FTP details! {}'.format(e))
            return

        main_window_rect = self.geometry()
        log_window_x = main_window_rect.x() + main_window_rect.width() + 10
        log_window_y = main_window_rect.y()
        self.log_window.move(log_window_x, log_window_y)
        self.log_window.clear()
        self.log_window.show()
        self.rollback_button.setEnabled(False)
        self.upgrade_button.setEnabled(True)
        self.downloadThread = FTPDownloadThread(host, username, password, "/", file_path)
        self.downloadThread.progress.connect(self.progress_bar.setValue)
        self.downloadThread.finished.connect(self.on_upgrade_finished)
        self.downloadThread.progressMsg.connect(self.log)
        self.downloadThread.start()

    def on_upgrade_finished(self, success):
        if success:
            QMessageBox.information(self, 'Upgrade Complete', 'File has been upgrade successfully.')
        else:
            QMessageBox.critical(self, 'Upgrade Failed', 'An error occurred during the upgrade process.')
        self.upgrade_button.setEnabled(True)
        self.progress_bar.setValue(0)
        self.log_window.close()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = FTPUpgradeWindow()
    window.show()
    sys.exit(app.exec())

正常使用用

import sys
import ftplib
import shutil

from datetime import datetime

from PySide6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
    QLineEdit, QPushButton, QProgressBar, QMessageBox, QFrame, QFileDialog, QComboBox, QPlainTextEdit, QDialog,
)
from db import Sqlite3Database
from PySide6.QtGui import QIcon, QFont
from PySide6.QtCore import QThread, Signal, Qt, QTimer, QPropertyAnimation, QRect
import os

from ftp import FTPWalk


def ftp_mkdir_recursive(ftp: ftplib.FTP, remote_directory: str):
    """
    递归创建远程 FTP 目录,如果不存在则创建
    :param ftp: FTP 对象
    :param remote_directory: 远程目录路径
    """
    dirs = remote_directory.split('/')
    current_path = ''
    for directory in dirs:
        if directory not in ["",".","./"]:  # 跳过空字符串
            current_path += '/' + directory
            try:
                ftp.cwd(current_path)  # 尝试切换到该目录
            except ftplib.error_perm:
                ftp.mkd(current_path)
                ftp.cwd(current_path)  # 切换到刚创建的目录

def ftp_upload_recursive(ftp: ftplib.FTP, local_dir: str, remote_dir: str):
    """
    递归上传本地目录到 FTP 服务器,并创建不存在的远程目录
    :param ftp: FTP 对象
    :param local_dir: 本地目录路径
    :param remote_dir: 远程 FTP 目录路径
    """
    ftp_mkdir_recursive(ftp, remote_dir)
    for root, dirs, files in os.walk(local_dir):
        rel_path = os.path.relpath(root, local_dir)
        rel_remote_path = os.path.join(remote_dir, rel_path).replace('\\', '/')
        for dir_name in dirs:
            ftp_mkdir_recursive(ftp, f"{rel_remote_path}/{dir_name}")
        for file_name in files:
            local_file_path = os.path.join(root, file_name)
            remote_file_path = f"{rel_remote_path}/{file_name}".replace('\\', '/')
            with open(local_file_path, 'rb') as file:
                print(f"Uploading {local_file_path} to {remote_file_path}")
                ftp.storbinary(f'STOR {remote_file_path}', file)

def ftp_directory_exists(ftp: ftplib.FTP, directory: str) -> bool:
    """
    检查 FTP 服务器上的目录是否存在
    :param ftp: FTP 对象
    :param directory: 需要检查的目录路径
    :return: 如果目录存在则返回 True,否则返回 False
    """
    current_dir = ftp.pwd()  # 记住当前所在目录
    try:
        ftp.cwd(directory)  # 尝试切换到目标目录
        ftp.cwd(current_dir)  # 成功后返回原始目录
        return True
    except ftplib.error_perm as e:
        if str(e).startswith('550'):
            return False
        else:
            raise e  # 如果是其他错误,抛出异常

class LogWindow(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Upgrade Progress")
        self.resize(500, 350)

        # 设置样式表美化界面
        self.setStyleSheet("""
            QDialog {
                background-color: #f2f2f2;
                border-radius: 10px;
            }
            QPlainTextEdit {
                background-color: #1e1e1e;
                color: #dcdcdc;
                border-radius: 5px;
                padding: 10px;
                font-family: Consolas, monospace;
                font-size: 14px;
            }
            QPushButton {
                background-color: #4caf50;
                color: white;
                border-radius: 5px;
                padding: 8px 15px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
        """)

        # 布局
        main_layout = QVBoxLayout()

        # 添加日志显示窗口
        self.log_edit = QPlainTextEdit(self)
        self.log_edit.setReadOnly(True)
        main_layout.addWidget(self.log_edit)

        # 底部的关闭按钮
        self.close_button = QPushButton("Close", self)
        self.close_button.clicked.connect(self.close)

        # 添加按钮布局
        button_layout = QHBoxLayout()
        button_layout.addStretch(1)  # 左侧扩展
        button_layout.addWidget(self.close_button)  # 右侧关闭按钮
        main_layout.addLayout(button_layout)

        self.setLayout(main_layout)

    def clear(self):
        self.log_edit.clear()

    def append_log(self, text):
        self.log_edit.appendPlainText(text)
        self.log_edit.verticalScrollBar().setValue(self.log_edit.verticalScrollBar().maximum())

class FTPDownloadThread(QThread):
    progress = Signal(int)
    finished = Signal(bool)
    progressMsg = Signal(str)

    def __init__(self, host, username, password, file_path, save_path):
        super().__init__()
        self.host = host
        self.username = username
        self.password = password
        self.file_path = file_path
        self.save_path = save_path

    def run(self):
        try:
            ftp = ftplib.FTP(self.host,timeout=3)
            ftp.login(self.username, self.password)
            bk = datetime.now().strftime("%Y%m%d%H%M%S")
            for check in [ "/mnt/flash","/"] :
                if not ftp_directory_exists(ftp,check):
                   continue
                for path, _, file in FTPWalk(ftp).walk(check):
                    self.progress.emit(file)
                    for _file in file:
                        Path = path + "/" if path != "/" else "/"
                        os.makedirs("app/" + bk+"/" + Path,exist_ok=True)
                        self.progressMsg.emit(f"Create Backup Path: app/{datetime.now().strftime('%Y%m%d%H%M%S')}"
                                             f"/{Path}")
                        File = Path + _file
                        size = 0
                        def callback(line):
                            nonlocal size
                            file_info = line.split(maxsplit=8)
                            if len(file_info) >= 4:
                                size = int(file_info[4])
                        ftp.retrlines(f"LIST {File}",callback)
                        self.progressMsg.emit(f"{File} Size: {size}")
                        with open("app/"+bk+"/"+File, 'wb') as f:
                            def handle_block(block):
                                nonlocal size
                                f.write(block)
                                self.progress.emit(int(f.tell() / size * 100))
                            ftp.retrbinary(f"RETR {File}", handle_block)
                break
            ftp.quit()
            self.finished.emit(True)
        except Exception as e:
            print(f"Error: {e}")
            self.finished.emit(False)

class FTPUploadThread(QThread):
    progress = Signal(int)
    finished = Signal(bool)
    progressMsg = Signal(str)

    def __init__(self, host: str, username: str, password: str, remotePath: str, save_path: str):
        super().__init__()
        self.host = host
        self.username = username
        self.password = password
        self.file_path = remotePath
        self.save_path = save_path

    def run(self):
        try:
            ftp = ftplib.FTP(self.host,timeout=3)
            ftp.login(self.username, self.password)
            current_dir = os.getcwd()
            os.chdir(self.save_path)
            self.progressMsg.emit("开始扫描升级文件夹")
            for check in ["/mnt/flash","/"]:
                if ftp_directory_exists(ftp, check):
                    self.progressMsg.emit("开始检查文件是否合法")
                    for dirpath, dirnames, filenames in os.walk("."):
                        for filename in filenames:
                            total_size = os.path.getsize(dirpath + "/" + filename)
                            tmp = dirpath
                            self.progress.emit(tmp)
                            if tmp != ".":
                                self.progressMsg.emit(f"开始创建合法目录:{tmp.replace('\\','/')}")
                                ftp_mkdir_recursive(ftp,f"{check}/{tmp}".replace("\\","/"))
                                self.progressMsg.emit(f"完成创建合法目录:{tmp.replace('\\','/')}")
                            self.progressMsg.emit(f"{dirpath + "/" + filename}")
                            if filename.find(".db") != -1:
                                self.progressMsg.emit(f"{dirpath}/{filename} 复写数据库开始")
                                try:
                                    with open(current_dir+"/"+filename, 'wb') as f:
                                        def handle_block(block):
                                            f.write(block)
                                        ftp.retrbinary(f"RETR {check}/config/{filename}", callback=handle_block)
                                    newDB = Sqlite3Database(dirpath + "/" + filename)
                                    oldDB = Sqlite3Database(current_dir+"/"+filename)
                                    oldDB.patch_database("V0",6,"ID",0,newDB)
                                    self.progressMsg.emit(f"{dirpath}/{filename} 复写数据库完成")
                                    dbk =  filename + "." + datetime.now().strftime("%Y%m%d%H%M%S")
                                    self.progressMsg.emit(f"备份数据库名称: {dbk}")
                                    newDB.close()
                                    oldDB.close()
                                    shutil.copy(current_dir+"/"+filename,current_dir+"/"+dbk)
                                except ftplib.error_perm as e:
                                       self.progressMsg.emit(f"Error: {e}")
                            self.progressMsg.emit(f"开始上传:{dirpath}/{filename}")
                            with open(f"{dirpath + "/" + filename}", 'rb') as f:
                                track_length = 0
                                def _handle_block(block):
                                    nonlocal track_length
                                    track_length = track_length + len(block)
                                    self.progress.emit((track_length / total_size) * 100)
                                ftp.storbinary(f"STOR "
                                               f"{check+"/" if check != "/" else check +tmp+"/"+filename}".replace(
                                    "\\",
                                    "/"), f,
                                    callback=_handle_block)
                            self.progressMsg.emit(f"完成上传:{dirpath}/{filename}")
                    break
            os.chdir(current_dir)
            ftp.quit()
            self.finished.emit(True)
        except Exception as e:
            self.progressMsg.emit(f"Error: {e}")
            self.finished.emit(False)


def progress_bar_style():
    return """
        QProgressBar {
            border: 1px solid #007BFF;  /* 简单的边框 */
            border-radius: 0;  /* 去掉圆角 */
            text-align: center;
        }
        QProgressBar::chunk {
            background-color: #007BFF;  /* 进度条填充色 */
        }
    """


def button_style():
    return """
        QPushButton {
            background-color: #007BFF;  /* 按钮背景色 */
            color: white;  /* 按钮文字颜色 */
            font-size: 16px;
            padding: 8px;  /* 按钮内边距 */
            border: none;  /* 去掉边框 */
        }
        QPushButton:hover {
            background-color: #0056b3;  /* 鼠标悬停时的背景色 */
        }
    """


def input_style():
    return """
        QLineEdit {
            border: 1px solid gray;  /* 简单的边框 */
            border-radius: 0;  /* 去掉圆角 */
            padding: 5px;
            font-size: 14px;
        }
        QLineEdit:focus {
            border-color: #007BFF;  /* 聚焦时的边框颜色 */
        }
    """
def combobox_style():
    return """
            QComboBox {
                font-size: 14px;
                padding: 5px;
                border: 2px solid #007BFF;
                border-radius: 5px;
                background-color: white;
            }
            QComboBox QAbstractItemView {
                border: 1px solid #007BFF;
                background-color: #f9f9f9;
                selection-background-color: #007BFF;
                selection-color: white;
            }
            QComboBox::drop-down {
                subcontrol-origin: padding;
                subcontrol-position: top right;
                width: 30px;
                border-left-width: 1px;
                border-left-color: #007BFF;
                border-left-style: solid;
                border-top-right-radius: 5px;
                border-bottom-right-radius: 5px;
                background-color: #007BFF;
            }
        """

class FTPUpgradeWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.downloadThread = None
        self.upgrade_button = None
        self.progress_bar = None
        self.rollback_button = None
        self.browse_button = None
        self.file_input = None
        self.password_input = None
        self.user_input = None
        self.host_input = None
        self.uploadThread = None
        self.log_window = LogWindow()
        self.log_window.setWindowModality(Qt.WindowModality.NonModal)
        self.log_window.setMaximumSize(800,600)
        self.log_window.setMinimumSize(800,600)
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('FTP Upgrade')
        self.setWindowIcon(QIcon('ftp_icon.png'))

        layout = QVBoxLayout()

        frame = QFrame(self)
        frame.setFrameShape(QFrame.NoFrame)  # 不使用边框
        frame_layout = QVBoxLayout()

        self.host_input = QComboBox(self)
        self.host_input.addItems(["近端机 AU ftp://192.168.1.2",
                                  "近端机 AU ftp://192.168.1.113",
                                  "远端机 RU ftp://192.168.98.98",
                                  "测试机 ftp://localhost"])
        self.host_input.setPlaceholderText('Hostname (ftp://hostname)')
        self.host_input.setStyleSheet(combobox_style())
        self.host_input.setEditable(True)

        self.user_input = QLineEdit(self)
        self.user_input.setPlaceholderText('Username')
        self.user_input.setStyleSheet(input_style())

        self.user_input.setText("root")

        self.password_input = QLineEdit(self)
        self.password_input.setPlaceholderText('Password')
        self.password_input.setEchoMode(QLineEdit.Password)  # 隐藏密码输入
        self.password_input.setStyleSheet(input_style())

        self.password_input.setText("root")

        self.file_input = QLineEdit(self)
        self.file_input.setPlaceholderText('File Path (dir)')
        self.file_input.setStyleSheet(input_style())

        self.file_input.setText(os.getcwd()+"\\upgrade")

        # 文件选择按钮
        self.browse_button = QPushButton('Browse...', self)
        self.browse_button.setStyleSheet(button_style())
        self.browse_button.clicked.connect(self.browse_file)

        self.progress_bar = QProgressBar(self)
        self.progress_bar.setValue(0)
        self.progress_bar.setStyleSheet(progress_bar_style())

        self.upgrade_button = QPushButton('Start Upgrade', self)
        self.upgrade_button.setStyleSheet(button_style())
        self.upgrade_button.clicked.connect(self.start_upgrade)

        self.rollback_button = QPushButton('Start Backup', self)
        self.rollback_button.setStyleSheet(button_style())
        self.rollback_button.clicked.connect(self.rollback)
        self.rollback_button.setEnabled(True)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.upgrade_button)
        button_layout.addWidget(self.rollback_button)

        frame_layout.addWidget(QLabel('Enter FTP Details:'))
        frame_layout.addWidget(self.host_input)
        frame_layout.addWidget(self.user_input)
        frame_layout.addWidget(self.password_input)
        frame_layout.addWidget(self.file_input)
        frame_layout.addWidget(self.browse_button)  # 添加浏览按钮
        frame_layout.addWidget(self.progress_bar)
        frame_layout.addLayout(button_layout)

        frame.setLayout(frame_layout)

        layout.addWidget(frame)
        self.setLayout(layout)
        self.setMaximumSize(400, 300)
        self.setMinimumSize(400, 300)
        font = QFont("Arial", 10)
        self.setFont(font)

    def browse_file(self):
        dirName = QFileDialog.getExistingDirectory(self, "Select Dir", "")
        if dirName:
            self.file_input.setText(dirName)  # 设置选择的文件路径

    def start_upgrade(self):
        try:
            host = self.host_input.currentText().strip().split('://')[1]
            username = self.user_input.text().strip()
            password = self.password_input.text().strip()
            file_path = self.file_input.text().strip()
        except Exception as e:
            QMessageBox.warning(self, 'Input Error', 'Please enter valid FTP details! {}'.format(e))
            return

        main_window_rect = self.geometry()
        log_window_x = main_window_rect.x() + main_window_rect.width() + 10  # 在主窗口右侧10像素
        log_window_y = main_window_rect.y()
        self.log_window.move(log_window_x, log_window_y)
        self.log_window.show()
        self.rollback_button.setEnabled(False)
        self.upgrade_button.setEnabled(False)
        self.uploadThread = FTPUploadThread(host, username, password, "/", file_path)  # 你可以选择保存路径
        self.uploadThread.progress.connect(self.progress_bar.setValue)
        self.uploadThread.finished.connect(self.on_upgrade_finished)
        self.uploadThread.progressMsg.connect(self.log)
        self.uploadThread.start()

    def log(self,msg:str):
        self.log_window.append_log(msg)

    def rollback(self):
        try:
            host = self.host_input.currentText().strip().split('://')[1]
            username = self.user_input.text().strip()
            password = self.password_input.text().strip()
            file_path = self.file_input.text().strip()
        except Exception as e:
            QMessageBox.warning(self, 'Input Error', 'Please enter valid FTP details! {}'.format(e))
            return
        main_window_rect = self.geometry()
        log_window_x = main_window_rect.x() + main_window_rect.width() + 10
        log_window_y = main_window_rect.y()
        self.log_window.move(log_window_x, log_window_y)
        self.log_window.clear()
        self.log_window.show()
        self.rollback_button.setEnabled(False)
        self.upgrade_button.setEnabled(False)
        self.downloadThread = FTPDownloadThread(host, username, password, "/", file_path)
        self.downloadThread.progress.connect(self.progress_bar.setValue)
        self.downloadThread.finished.connect(self.backup_finished)
        self.downloadThread.progressMsg.connect(self.log)
        self.downloadThread.start()

    def backup_finished(self,success:bool):
        if success:
            QMessageBox.information(self, 'backup Complete', 'File has been backup successfully.')
        else:
            QMessageBox.critical(self, 'backup Failed', 'An error occurred during the backup process.')
        self.rollback_button.setEnabled(True)
        self.upgrade_button.setEnabled(True)
        self.progress_bar.setValue(0)
        self.log_window.close()

    def on_upgrade_finished(self, success):
        if success:
            QMessageBox.information(self, 'Upgrade Complete', 'File has been upgrade successfully.')
        else:
            QMessageBox.critical(self, 'Upgrade Failed', 'An error occurred during the upgrade process.')
        self.upgrade_button.setEnabled(True)
        self.rollback_button.setEnabled(True)
        self.progress_bar.setValue(0)
        self.log_window.close()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = FTPUpgradeWindow()
    window.show()
    sys.exit(app.exec())

在这里插入图片描述

调整一下效果


网站公告

今日签到

点亮在社区的每一天
去签到