feat: simplify backup filename timestamps to hourly granularity by removing minutes and seconds.
This commit is contained in:
@@ -263,10 +263,17 @@ class BackupStrategy(ABC):
|
|||||||
else:
|
else:
|
||||||
self.log("Pembersihan selesai. Tidak ada file lama ditemukan.")
|
self.log("Pembersihan selesai. Tidak ada file lama ditemukan.")
|
||||||
|
|
||||||
def _get_dated_dest_dir(self, base_dest):
|
def _get_dated_dest_dir(self, base_dest, job_name=None):
|
||||||
"""Creates and returns YYYY/MM/DD subfolder path inside base_dest."""
|
"""Creates and returns JobName/YYYY/MM/DD subfolder path inside base_dest."""
|
||||||
|
|
||||||
|
# Add Job Name folder if provided
|
||||||
|
if job_name:
|
||||||
|
# Sanitize job name for folder validity
|
||||||
|
safe_job_name = "".join(c for c in job_name if c.isalnum() or c in (' ', '.', '_', '-')).strip()
|
||||||
|
base_dest = os.path.join(base_dest, safe_job_name)
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
# Create structure: base/YYYY/MM/DD
|
# Create structure: base/JobName/YYYY/MM/DD
|
||||||
dated_path = os.path.join(base_dest, now.strftime("%Y"), now.strftime("%m"), now.strftime("%d"))
|
dated_path = os.path.join(base_dest, now.strftime("%Y"), now.strftime("%m"), now.strftime("%d"))
|
||||||
if not os.path.exists(dated_path):
|
if not os.path.exists(dated_path):
|
||||||
os.makedirs(dated_path, exist_ok=True)
|
os.makedirs(dated_path, exist_ok=True)
|
||||||
@@ -286,8 +293,12 @@ class FileBackup(BackupStrategy):
|
|||||||
if not os.path.exists(source):
|
if not os.path.exists(source):
|
||||||
raise FileNotFoundError("Sumber tidak ditemukan: {}".format(source))
|
raise FileNotFoundError("Sumber tidak ditemukan: {}".format(source))
|
||||||
|
|
||||||
# Use dated directory
|
if not os.path.exists(source):
|
||||||
target_dest = self._get_dated_dest_dir(dest)
|
raise FileNotFoundError("Sumber tidak ditemukan: {}".format(source))
|
||||||
|
|
||||||
|
# Use dated directory with Job Name
|
||||||
|
job_name = config.get('name')
|
||||||
|
target_dest = self._get_dated_dest_dir(dest, job_name)
|
||||||
|
|
||||||
self.log("Memulai Backup File: {} -> {}".format(source, target_dest))
|
self.log("Memulai Backup File: {} -> {}".format(source, target_dest))
|
||||||
|
|
||||||
@@ -414,8 +425,9 @@ class MySQLBackup(BackupStrategy):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Use dated directory
|
# Use dated directory with Job Name
|
||||||
target_dest = self._get_dated_dest_dir(dest)
|
job_name = config.get('name')
|
||||||
|
target_dest = self._get_dated_dest_dir(dest, job_name)
|
||||||
|
|
||||||
# Log tool location for debugging
|
# Log tool location for debugging
|
||||||
self.log("Menggunakan mysqldump: {}".format(mysqldump_path))
|
self.log("Menggunakan mysqldump: {}".format(mysqldump_path))
|
||||||
@@ -551,8 +563,9 @@ class PostgresBackup(BackupStrategy):
|
|||||||
dest = config.get('dest')
|
dest = config.get('dest')
|
||||||
all_databases = config.get('all_databases', False)
|
all_databases = config.get('all_databases', False)
|
||||||
|
|
||||||
# Use dated directory
|
# Use dated directory with Job Name
|
||||||
target_dest = self._get_dated_dest_dir(dest)
|
job_name = config.get('name')
|
||||||
|
target_dest = self._get_dated_dest_dir(dest, job_name)
|
||||||
|
|
||||||
# Detect Server Version
|
# Detect Server Version
|
||||||
self.log("Mendeteksi versi server Postgres di {}:{}...".format(host, port))
|
self.log("Mendeteksi versi server Postgres di {}:{}...".format(host, port))
|
||||||
|
|||||||
68
main.py
68
main.py
@@ -739,6 +739,9 @@ class BackupApp(QMainWindow):
|
|||||||
|
|
||||||
def new_job(self):
|
def new_job(self):
|
||||||
job = ConfigManager.create_new_job()
|
job = ConfigManager.create_new_job()
|
||||||
|
# Add timestamp prefix as requested
|
||||||
|
# "kalau buat daftar pekerjaan baru, tambahkan prefix tanggal dan jam"
|
||||||
|
job['name'] = "{} {}".format(time.strftime("%Y-%m-%d %H:%M"), job['name'])
|
||||||
self.jobs.append(job)
|
self.jobs.append(job)
|
||||||
self.refresh_job_list()
|
self.refresh_job_list()
|
||||||
|
|
||||||
@@ -1384,6 +1387,30 @@ class BackupApp(QMainWindow):
|
|||||||
# Disable if already activated
|
# Disable if already activated
|
||||||
if not self.trial_mode:
|
if not self.trial_mode:
|
||||||
self.activate_action.setEnabled(False)
|
self.activate_action.setEnabled(False)
|
||||||
|
# Menu Bar
|
||||||
|
menubar = self.menuBar()
|
||||||
|
|
||||||
|
# File Menu
|
||||||
|
file_menu = menubar.addMenu('File')
|
||||||
|
exit_action = QAction('Keluar', self)
|
||||||
|
exit_action.triggered.connect(self.close)
|
||||||
|
file_menu.addAction(exit_action)
|
||||||
|
|
||||||
|
# Settings Menu (Pengaturan)
|
||||||
|
settings_menu = menubar.addMenu('Pengaturan')
|
||||||
|
|
||||||
|
# Auto Start Action
|
||||||
|
self.auto_start_action = QAction('Auto Start saat Windows', self)
|
||||||
|
self.auto_start_action.setCheckable(True)
|
||||||
|
self.auto_start_action.setChecked(self.check_auto_start_status())
|
||||||
|
self.auto_start_action.triggered.connect(self.toggle_auto_start)
|
||||||
|
settings_menu.addAction(self.auto_start_action)
|
||||||
|
|
||||||
|
# Help Menu
|
||||||
|
help_menu = menubar.addMenu('Bantuan')
|
||||||
|
about_action = QAction('Tentang', self)
|
||||||
|
about_action.triggered.connect(self.show_about)
|
||||||
|
help_menu.addAction(about_action)
|
||||||
|
|
||||||
quit_action = QAction("Keluar", self)
|
quit_action = QAction("Keluar", self)
|
||||||
quit_action.triggered.connect(self.quit_app)
|
quit_action.triggered.connect(self.quit_app)
|
||||||
@@ -1412,6 +1439,44 @@ class BackupApp(QMainWindow):
|
|||||||
except: pass
|
except: pass
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
|
def check_auto_start_status(self):
|
||||||
|
"""Check if registry key exists for auto start"""
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_READ)
|
||||||
|
winreg.QueryValueEx(key, "ProBackupXP")
|
||||||
|
winreg.CloseKey(key)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def toggle_auto_start(self, checked):
|
||||||
|
"""Add or remove registry key for auto start"""
|
||||||
|
import winreg
|
||||||
|
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
|
||||||
|
app_name = "ProBackupXP"
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_ALL_ACCESS)
|
||||||
|
if checked:
|
||||||
|
# Add to registry
|
||||||
|
# Use sys.executable for the running exe path
|
||||||
|
exe_path = '"{}"'.format(os.path.abspath(sys.executable))
|
||||||
|
winreg.SetValueEx(key, app_name, 0, winreg.REG_SZ, exe_path)
|
||||||
|
self.log("Auto Start diaktifkan.")
|
||||||
|
else:
|
||||||
|
# Remove from registry
|
||||||
|
try:
|
||||||
|
winreg.DeleteValue(key, app_name)
|
||||||
|
self.log("Auto Start dinonaktifkan.")
|
||||||
|
except:
|
||||||
|
pass # Key might not exist
|
||||||
|
winreg.CloseKey(key)
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Error", "Gagal mengubah pengaturan registry:\n{}".format(e))
|
||||||
|
# Revert checkbox state if failed
|
||||||
|
self.auto_start_action.setChecked(not checked)
|
||||||
|
|
||||||
def show_window(self):
|
def show_window(self):
|
||||||
self.show()
|
self.show()
|
||||||
self.raise_()
|
self.raise_()
|
||||||
@@ -1492,6 +1557,9 @@ if __name__ == "__main__":
|
|||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setQuitOnLastWindowClosed(False) # For tray icon
|
app.setQuitOnLastWindowClosed(False) # For tray icon
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user