[backup] improvement: 'single mode' should only remove self generated snapshots

This commit is contained in:
Vinicius Moreira
2022-03-29 17:44:00 -03:00
parent 075559a437
commit da8a4e6547
11 changed files with 55 additions and 21 deletions

View File

@@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Improvements ### Improvements
- General - General
- code refactoring - code refactoring
- backup:
- single mode: only removing self generated snapshots (now the snapshots are associated with the comment "<bauh>") [#244](https://github.com/vinifmor/bauh/issues/244)
- Arch - Arch
- text length of some popups reduced - text length of some popups reduced

View File

@@ -438,7 +438,7 @@ disk:
after_upgrade: false # it trims the disk after a successful packages upgrade (`fstrim -a -v`). 'true' will automatically perform the trim and 'null' will display a confirmation dialog after_upgrade: false # it trims the disk after a successful packages upgrade (`fstrim -a -v`). 'true' will automatically perform the trim and 'null' will display a confirmation dialog
backup: backup:
enabled: true # generate timeshift snapshots before an action (if timeshift is installed on the system) enabled: true # generate timeshift snapshots before an action (if timeshift is installed on the system)
mode: 'incremental' # incremental=generates a new snapshot based on another pre-exising one. 'only_one'=deletes all pre-existing snapshots and generates a fresh one. mode: 'incremental' # incremental=generates a new snapshot based on another pre-exising one. 'only_one'=deletes all pre-existing self created snapshots and generates a fresh one.
install: null # defines if the backup should be performed before installing a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation install: null # defines if the backup should be performed before installing a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation
uninstall: null # defines if the backup should be performed before uninstalling a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation uninstall: null # defines if the backup should be performed before uninstalling a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation
upgrade: null # defines if the backup should be performed before upgrading a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation upgrade: null # defines if the backup should be performed before upgrading a package. Allowed values: null (a dialog will be displayed asking if a snapshot should be generated), true: generates the backup without asking. false: disables the backup for this operation

View File

@@ -1,7 +1,11 @@
import re
import shutil import shutil
from typing import Optional from typing import Optional, Generator
from bauh.commons.system import SimpleProcess from bauh import __app_name__
from bauh.commons.system import SimpleProcess, new_root_subprocess
RE_SNAPSHOTS = re.compile(r'\d+\s+>\s+([\w\-_]+)\s+.+<{}>'.format(__app_name__))
def is_available() -> bool: def is_available() -> bool:
@@ -12,5 +16,23 @@ def delete_all_snapshots(root_password: Optional[str]) -> SimpleProcess:
return SimpleProcess(['timeshift', '--delete-all', '--scripted'], root_password=root_password) return SimpleProcess(['timeshift', '--delete-all', '--scripted'], root_password=root_password)
def delete(snapshot_name: str, root_password: Optional[str]) -> SimpleProcess:
return SimpleProcess(('timeshift', '--delete', '--snapshot', snapshot_name),
shell=True, root_password=root_password)
def create_snapshot(root_password: Optional[str], mode: str) -> SimpleProcess: def create_snapshot(root_password: Optional[str], mode: str) -> SimpleProcess:
return SimpleProcess(['timeshift', '--create', '--scripted', '--{}'.format(mode)], root_password=root_password) return SimpleProcess(('timeshift', '--create', '--scripted', f'--{mode}', '--comments', f'<{__app_name__}>'),
root_password=root_password)
def read_created_snapshots(root_password: Optional[str]) -> Generator[str, None, None]:
proc = new_root_subprocess(cmd=('timeshift', '--list'), root_password=root_password, shell=True)
proc.wait()
if proc.returncode == 0:
output = '\n'.join((o.decode() for o in proc.stdout))
if output:
for name in RE_SNAPSHOTS.findall(output):
yield name

View File

@@ -5,7 +5,7 @@ import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta
from io import StringIO from io import StringIO
from pathlib import Path from pathlib import Path
from typing import List, Type, Set, Tuple, Optional, Iterable from typing import List, Type, Set, Tuple, Optional
import requests import requests
from PyQt5.QtCore import QThread, pyqtSignal, QObject from PyQt5.QtCore import QThread, pyqtSignal, QObject
@@ -140,16 +140,26 @@ class AsyncAction(QThread, ProcessWatcher):
handler = ProcessHandler(self) handler = ProcessHandler(self)
if app_config['backup']['mode'] == 'only_one': if app_config['backup']['mode'] == 'only_one':
self.change_substatus('[{}] {}'.format(self.i18n['core.config.tab.backup'].lower(), self.i18n['action.backup.substatus.delete'])) previous_snapshots = tuple(timeshift.read_created_snapshots(root_password))
deleted, _ = handler.handle_simple(timeshift.delete_all_snapshots(root_password))
if not deleted and not self.request_confirmation(title=self.i18n['core.config.tab.backup'], if previous_snapshots:
body='{}. {}'.format(self.i18n['action.backup.error.delete'], substatus = f"[{self.i18n['core.config.tab.backup'].lower()}] {self.i18n['action.backup.substatus.delete']}"
self.i18n['action.backup.error.proceed']), self.change_substatus(substatus)
confirmation_label=self.i18n['yes'].capitalize(),
deny_label=self.i18n['no'].capitalize()): delete_failed = False
self.change_substatus('') for snapshot in reversed(previous_snapshots):
return False deleted, _ = handler.handle_simple(timeshift.delete(snapshot, root_password))
if not deleted:
delete_failed = True
if delete_failed and not self.request_confirmation(title=self.i18n['core.config.tab.backup'],
body=f"{self.i18n['action.backup.error.delete']}. "
f"{self.i18n['action.backup.error.proceed']}",
confirmation_label=self.i18n['yes'].capitalize(),
deny_label=self.i18n['no'].capitalize()):
self.change_substatus('')
return False
self.change_substatus('[{}] {}'.format(self.i18n['core.config.tab.backup'].lower(), self.i18n['action.backup.substatus.create'])) self.change_substatus('[{}] {}'.format(self.i18n['core.config.tab.backup'].lower(), self.i18n['action.backup.substatus.create']))
created, _ = handler.handle_simple(timeshift.create_snapshot(root_password, app_config['backup']['type'])) created, _ = handler.handle_simple(timeshift.create_snapshot(root_password, app_config['backup']['type']))

View File

@@ -45,7 +45,7 @@ Ukraine=Ukraine
United Kingdom=United Kingdom United Kingdom=United Kingdom
United States=United States United States=United States
action.backup.error.create=It was not possible to generate a new system copy action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete the old system copies action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ? action.backup.error.proceed=Proceed anyway ?
action.backup.invalid_mode=Invalid backup mode action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ? action.backup.msg=Do you want to generate a system copy before proceeding ?

View File

@@ -45,7 +45,7 @@ Ukraine=Ukraine
United Kingdom=United Kingdom United Kingdom=United Kingdom
United States=United States United States=United States
action.backup.error.create=It was not possible to generate a new system copy action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete the old system copies action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ? action.backup.error.proceed=Proceed anyway ?
action.backup.invalid_mode=Invalid backup mode action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ? action.backup.msg=Do you want to generate a system copy before proceeding ?

View File

@@ -45,7 +45,7 @@ Ukraine=Ukraine
United Kingdom=United Kingdom United Kingdom=United Kingdom
United States=United States United States=United States
action.backup.error.create=It was not possible to generate a new system copy action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete the old system copies action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ? action.backup.error.proceed=Proceed anyway ?
action.backup.invalid_mode=Invalid backup mode action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ? action.backup.msg=Do you want to generate a system copy before proceeding ?

View File

@@ -45,7 +45,7 @@ Ukraine=Ucrania
United Kingdom=Reino Unido United Kingdom=Reino Unido
United States=Estados Unidos United States=Estados Unidos
action.backup.error.create=No fue posible generar una nueva copia de seguridad action.backup.error.create=No fue posible generar una nueva copia de seguridad
action.backup.error.delete=No fue posible eliminar las copias de seguridad antiguas del sistema action.backup.error.delete=No fue posible eliminar todas las copias de seguridad antiguas del sistema
action.backup.error.proceed=¿Continuar de todos modos? action.backup.error.proceed=¿Continuar de todos modos?
action.backup.invalid_mode=Modo de copia de seguridad inválido action.backup.invalid_mode=Modo de copia de seguridad inválido
action.backup.msg=¿Desea generar una copia de seguridad del sistema antes de continuar? action.backup.msg=¿Desea generar una copia de seguridad del sistema antes de continuar?

View File

@@ -45,7 +45,7 @@ Ukraine=Ukraine
United Kingdom=United Kingdom United Kingdom=United Kingdom
United States=United States United States=United States
action.backup.error.create=It was not possible to generate a new system copy action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete the old system copies action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ? action.backup.error.proceed=Proceed anyway ?
action.backup.invalid_mode=Invalid backup mode action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ? action.backup.msg=Do you want to generate a system copy before proceeding ?

View File

@@ -45,7 +45,7 @@ Ukraine=Ucrânia
United Kingdom=Reino Unido United Kingdom=Reino Unido
United States=Estados Unidos United States=Estados Unidos
action.backup.error.create=Não foi possível gerar uma nova cópia de segurança do sistema action.backup.error.create=Não foi possível gerar uma nova cópia de segurança do sistema
action.backup.error.delete=Não foi possível remover as cópias de segurança antigas do sistema action.backup.error.delete=Não foi possível remover todas as cópias de segurança antigas do sistema
action.backup.error.proceed=Continuar mesmo assim ? action.backup.error.proceed=Continuar mesmo assim ?
action.backup.invalid_mode=Modo de cópia de segurança inválido action.backup.invalid_mode=Modo de cópia de segurança inválido
action.backup.msg=Você deseja gerar uma cópia de segurança do sistema antes de proceder ? action.backup.msg=Você deseja gerar uma cópia de segurança do sistema antes de proceder ?

View File

@@ -45,7 +45,7 @@ Ukraine=Украина
United Kingdom=Великобритания United Kingdom=Великобритания
United States=Соединённые Штаты Америки United States=Соединённые Штаты Америки
action.backup.error.create=It was not possible to generate a new system copy action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete the old system copies action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ? action.backup.error.proceed=Proceed anyway ?
action.backup.invalid_mode=Invalid backup mode action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ? action.backup.msg=Do you want to generate a system copy before proceeding ?