Switch to Count-Based Retention and update UI
This commit is contained in:
@@ -219,8 +219,12 @@ class BackupStrategy(ABC):
|
||||
def is_cancelled(self):
|
||||
return self._cancel_flag
|
||||
|
||||
def cleanup_old_backups(self, dest, retention_days, job_name=None):
|
||||
if retention_days <= 0:
|
||||
def cleanup_old_backups(self, dest, retention_limit, job_name=None):
|
||||
"""
|
||||
Count-Based Retention: Keep 'retention_limit' newest files/archives.
|
||||
Delete the rest.
|
||||
"""
|
||||
if retention_limit <= 0:
|
||||
return
|
||||
|
||||
# SAFETY FIX: Scope cleanup to the specific Job Name folder
|
||||
@@ -229,31 +233,46 @@ class BackupStrategy(ABC):
|
||||
scan_root = os.path.join(dest, safe_job_name)
|
||||
else:
|
||||
# If no job name provided, DO NOT scan the root dest to prevent deleting user files
|
||||
# self.log("Warning: Nama pekerjaan tidak ada. Skip pembersihan demi keamanan.")
|
||||
return
|
||||
|
||||
if not os.path.exists(scan_root):
|
||||
return
|
||||
|
||||
self.log("Menjalankan pembersihan di {} (Retensi: {} hari)...".format(scan_root, retention_days))
|
||||
now = time.time()
|
||||
cutoff = now - (retention_days * 86400)
|
||||
self.log("Menjalankan pembersihan di {} (Batasan: {} file terbaru)...".format(scan_root, retention_limit))
|
||||
|
||||
all_backups = []
|
||||
|
||||
count = 0
|
||||
try:
|
||||
# Recursive scan for YYYY/MM/DD structure
|
||||
# 1. Collect all files recursively
|
||||
for root, dirs, files in os.walk(scan_root):
|
||||
for filename in files:
|
||||
filepath = os.path.join(root, filename)
|
||||
try:
|
||||
# Check modified time
|
||||
file_time = os.path.getmtime(filepath)
|
||||
if file_time < cutoff:
|
||||
os.remove(filepath)
|
||||
self.log("Menghapus backup lama: {}".format(filename))
|
||||
count += 1
|
||||
mtime = os.path.getmtime(filepath)
|
||||
all_backups.append((filepath, mtime))
|
||||
except:
|
||||
pass
|
||||
|
||||
# 2. Sort by time DESCENDING (Newest first)
|
||||
all_backups.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
# 3. Check if we have excess
|
||||
if len(all_backups) > retention_limit:
|
||||
files_to_delete = all_backups[retention_limit:]
|
||||
count = 0
|
||||
|
||||
for filepath, _ in files_to_delete:
|
||||
try:
|
||||
os.remove(filepath)
|
||||
self.log("Menghapus backup lama (Pruning): {}".format(os.path.basename(filepath)))
|
||||
count += 1
|
||||
except Exception as e:
|
||||
self.log("Gagal menghapus {}: {}".format(filename, e))
|
||||
self.log("Gagal menghapus {}: {}".format(os.path.basename(filepath), e))
|
||||
|
||||
if count > 0:
|
||||
self.log("Pembersihan selesai. Dihapus: {} file.".format(count))
|
||||
else:
|
||||
self.log("Jumlah file ({}) masih dibawah batas ({}). Tidak ada penghapusan.".format(len(all_backups), retention_limit))
|
||||
|
||||
# Optional: Remove empty folders after cleanup
|
||||
for root, dirs, files in os.walk(scan_root, topdown=False):
|
||||
@@ -267,11 +286,6 @@ class BackupStrategy(ABC):
|
||||
except Exception as e:
|
||||
self.log("Error saat pembersihan: {}".format(e))
|
||||
|
||||
if count > 0:
|
||||
self.log("Pembersihan selesai. Menghapus {} file lama.".format(count))
|
||||
else:
|
||||
self.log("Pembersihan selesai. Tidak ada file lama ditemukan.")
|
||||
|
||||
def _get_dated_dest_dir(self, base_dest, job_name=None):
|
||||
"""Creates and returns JobName/YYYY/MM/DD subfolder path inside base_dest."""
|
||||
|
||||
|
||||
4
main.py
4
main.py
@@ -501,10 +501,10 @@ class BackupApp(QMainWindow):
|
||||
|
||||
sched_layout.addStretch()
|
||||
sched_layout.addWidget(QLabel("| Retensi:"))
|
||||
self.retention_spin = QSpinBox()
|
||||
self.retention_spin.setRange(0, 3650)
|
||||
self.retention_spin.setSpecialValueText("Selamanya")
|
||||
self.retention_spin.setToolTip("Hapus backup lebih lama dari X hari. 0 = Simpan Selamanya.")
|
||||
self.retention_spin.setSuffix(" File")
|
||||
self.retention_spin.setToolTip("Simpan X file backup terbaru. File yang lebih lama akan dihapus.")
|
||||
self.create_spinbox_with_buttons(self.retention_spin, sched_layout)
|
||||
|
||||
sched_group.setLayout(sched_layout)
|
||||
|
||||
Reference in New Issue
Block a user