Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposed modification that I hope works and you like #1

Open
jambolo1970 opened this issue Dec 28, 2024 · 0 comments
Open

proposed modification that I hope works and you like #1

jambolo1970 opened this issue Dec 28, 2024 · 0 comments

Comments

@jambolo1970
Copy link

jambolo1970 commented Dec 28, 2024

import sys
import os
import shutil
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QComboBox, QPushButton, QProgressBar, QTextEdit, QFileDialog,
    QTableWidget, QTableWidgetItem
)
from PyQt5.QtCore import QThread, pyqtSignal
import subprocess

def is_ssd(device):
    """Check if the device is an SSD based on its rotational status."""
    try:
        device_name = os.path.basename(device.rstrip('/'))
        with open(f"/sys/block/{device_name}/queue/rotational", "r") as f:
            return f.read().strip() == "0"
    except FileNotFoundError:
        return False

class DefragWorker(QThread):
    progress = pyqtSignal(int)
    log = pyqtSignal(str)
    finished = pyqtSignal()

    def __init__(self, target):
        super().__init__()
        self.target = target
        self._running = True

    def run(self):
        if not os.path.exists(self.target):
            self.log.emit(f"Error: Target {self.target} does not exist.")
            self.finished.emit()
            return

        try:
            process = subprocess.Popen(
                ["pkexec", "e4defrag", "-v", self.target],
                stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True
            )

            total_steps = 100  # Simulated steps
            current_step = 0

            for line in process.stdout:
                if not self._running:
                    process.terminate()
                    self.log.emit("Process terminated by user.")
                    break

                self.log.emit(line.strip())

                # Simulate progress updates
                current_step = min(total_steps, current_step + 10)
                self.progress.emit(current_step)

            process.wait()

        except Exception as e:
            self.log.emit(f"Error: {e}")

        self.finished.emit()

    def stop(self):
        self._running = False

class UltraDefragGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("UltraDefrag GUI")
        self.setGeometry(100, 100, 800, 600)

        self.worker = None

        self.initUI()

    def initUI(self):
        main_layout = QVBoxLayout()

        # Top Layout: Directory/Partition Selection
        top_layout = QHBoxLayout()
        self.directory_label = QLabel("Select Partition/Directory:")
        self.directory_combo = QComboBox()
        self.load_partitions()

        self.browse_button = QPushButton("Browse...")
        self.browse_button.clicked.connect(self.browse_directory)

        top_layout.addWidget(self.directory_label)
        top_layout.addWidget(self.directory_combo)
        top_layout.addWidget(self.browse_button)

        # Middle Layout: Progress Bar and Buttons
        middle_layout = QHBoxLayout()
        self.progress_bar = QProgressBar()
        self.start_button = QPushButton("Start")
        self.start_button.clicked.connect(self.start_defrag)

        self.stop_button = QPushButton("Stop")
        self.stop_button.setEnabled(False)
        self.stop_button.clicked.connect(self.stop_defrag)

        middle_layout.addWidget(self.progress_bar)
        middle_layout.addWidget(self.start_button)
        middle_layout.addWidget(self.stop_button)

        # Bottom Layout: Logs and Table
        bottom_layout = QVBoxLayout()

        self.log_area = QTextEdit()
        self.log_area.setReadOnly(True)

        self.file_table = QTableWidget()
        self.file_table.setColumnCount(3)
        self.file_table.setHorizontalHeaderLabels(["File", "Size", "Fragments"])

        bottom_layout.addWidget(QLabel("Logs:"))
        bottom_layout.addWidget(self.log_area)
        bottom_layout.addWidget(QLabel("Fragmented Files:"))
        bottom_layout.addWidget(self.file_table)

        # Main Layout Assembly
        main_layout.addLayout(top_layout)
        main_layout.addLayout(middle_layout)
        main_layout.addLayout(bottom_layout)

        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

    def load_partitions(self):
        self.directory_combo.addItem("/")  # Root directory
        with open("/proc/mounts", "r") as f:
            for line in f:
                parts = line.split()
                if parts[0].startswith("/dev"):
                    self.directory_combo.addItem(parts[1])

    def browse_directory(self):
        directory = QFileDialog.getExistingDirectory(self, "Select Directory")
        if directory:
            self.directory_combo.addItem(directory)
            self.directory_combo.setCurrentText(directory)

    def start_defrag(self):
        target = self.directory_combo.currentText()

        # Verify if pkexec and e4defrag are installed
        if not shutil.which("pkexec"):
            self.log_area.append("Error: 'pkexec' is not installed or not in PATH.")
            return

        if not shutil.which("e4defrag"):
            self.log_area.append("Error: 'e4defrag' tool is not installed or not in PATH.")
            return

        if is_ssd(target):
            self.log_area.append(f"The device {target} is an SSD. Defragmentation is not necessary.")
            return

        # Run defragmentation as root using pkexec
        self.worker = DefragWorker(target)
        self.worker.progress.connect(self.update_progress)
        self.worker.log.connect(self.update_log)
        self.worker.finished.connect(self.defrag_finished)

        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)

        self.log_area.append(f"Starting defragmentation on {target}...")
        self.worker.start()

    def stop_defrag(self):
        if self.worker:
            self.worker.stop()

    def update_progress(self, value):
        self.progress_bar.setValue(value)

    def update_log(self, message):
        self.log_area.append(message)

    def defrag_finished(self):
        self.log_area.append("Defragmentation finished.")
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.worker = None

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_win = UltraDefragGUI()
    main_win.show()
    sys.exit(app.exec_())


I made it work only with ext-X extensions (2-3-4)
on linux mint it works, in case e4defrag intervenes it asks for root and its password.
on OpenSuse you have to run it directly as root
then from the terminal

su
 ‘password’
python3 file-defrag.py

are needed installed e4defrag and pkexec

hope this was useful
I wish it had had the little squares that changed colour depending on whether it was defragmented or not but I'm not good with python yet and it can certainly be improved...

I hope you'll pick up this little utility, which is very interesting and always useful even if on linux it has limitations between ssd disks and file systems that limit defragmentation, but a check doesn't hurt.

@jambolo1970 jambolo1970 changed the title proposta di aggiunta che spero funzioni proposed modification that I hope works and you like Jan 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant