8 Commits
3.0.2 ... 3.1.0

Author SHA1 Message Date
d2e982469b Log number of old backups removed 2023-04-30 11:41:37 +02:00
0dde6b8df9 Fix last_backup broken link detection 2023-04-30 11:32:35 +02:00
e45ae1b1b6 Decrease log verbosity 2023-04-30 11:02:59 +02:00
d1ccc33d0a Update gitignore 2023-04-30 10:41:51 +02:00
8b52115b4a Change journal log format 2023-04-30 10:40:18 +02:00
c02fd658bc Use systemd journal for logging 2023-04-29 22:26:38 +02:00
7d0125344f Update install file 2023-04-29 21:53:06 +02:00
3f2e133eff Change default config path 2023-04-29 21:50:35 +02:00
3 changed files with 41 additions and 21 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.idea/
test/

View File

@ -1,6 +1,6 @@
post_install() {
echo "An example configuration file is found in /etc/simple_backup/simple_backup.config."
echo "Copy it to ~/.simple_backup/simple_backup.config and modify it as needed"
echo "Copy it to ~/config/simple_backup/simple_backup.config and modify it as needed"
}
post_upgrade() {

View File

@ -1,20 +1,24 @@
#!/usr/bin/python3
# Import libraries
from dotenv import load_dotenv
import os
from functools import wraps
import dbus
from shutil import rmtree
import argparse
import configparser
import logging
from logging import StreamHandler
from logging.handlers import RotatingFileHandler
from timeit import default_timer
from subprocess import Popen, PIPE, STDOUT
from datetime import datetime
from tempfile import mkstemp
import dbus
from dotenv import load_dotenv
try:
from systemd import journal
except ImportError:
pass
load_dotenv()
@ -30,25 +34,23 @@ logging.getLogger().setLevel(logging.DEBUG)
logger = logging.getLogger(os.path.basename(__file__))
c_handler = StreamHandler()
try:
f_handler = RotatingFileHandler(f'{homedir}/.simple_backup/simple_backup.log', maxBytes=1024000, backupCount=5)
except Exception:
f_handler = None
c_handler.setLevel(logging.INFO)
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
logger.addHandler(c_handler)
if f_handler:
f_handler.setLevel(logging.INFO)
f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
f_handler.setFormatter(f_format)
logger.addHandler(f_handler)
try:
j_handler = journal.JournalHandler()
j_handler.setLevel(logging.INFO)
j_format = logging.Formatter('%(levelname)s - %(message)s')
j_handler.setFormatter(j_format)
logger.addHandler(j_handler)
except NameError:
pass
def timing(_logger):
def decorater_timing(func):
def decorator_timing(func):
@wraps(func)
def wrapper_timing(*args, **kwargs):
start = default_timer()
@ -63,7 +65,7 @@ def timing(_logger):
return wrapper_timing
return decorater_timing
return decorator_timing
class MyFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter):
@ -130,6 +132,7 @@ class Backup:
dirs.remove('last_backup')
n_backup = len(dirs) - 1
count = 0
if n_backup > self.keep:
logger.info('Removing old backups...')
@ -138,15 +141,26 @@ class Backup:
for i in range(n_backup - self.keep):
try:
rmtree(f'{self.output}/simple_backup/{dirs[i]}')
count += 1
except Exception:
logger.error(f'Error while removing backup {dirs[i]}')
if count == 1:
logger.info(f'Removed {count} backup')
else:
logger.info(f'Removed {count} backups')
def find_last_backup(self):
if os.path.islink(f'{self.output}/simple_backup/last_backup'):
try:
self._last_backup = os.readlink(f'{self.output}/simple_backup/last_backup')
except Exception:
logger.error('Previous backup could not be read')
logger.warning('Previous backup could not be read')
else:
logger.info('No previous backups available')
if not os.path.isdir(self._last_backup):
logger.warning('Previous backup could not be read')
# Function to read configuration file
@timing(logger)
@ -163,8 +177,8 @@ class Backup:
logger.error('Failed to remove last_backup link')
self._err_flag = True
inputs_handle, self._inputs_path = mkstemp(prefix='tmp_inputs', text=True)
exclude_handle, self._exclude_path = mkstemp(prefix='tmp_exclude', text=True)
_, self._inputs_path = mkstemp(prefix='tmp_inputs', text=True)
_, self._exclude_path = mkstemp(prefix='tmp_exclude', text=True)
with open(self._inputs_path, 'w') as fp:
for i in self.inputs:
@ -193,7 +207,10 @@ class Backup:
p = Popen(rsync, stdout=PIPE, stderr=STDOUT, shell=True)
output, _ = p.communicate()
logger.info(f'Output of rsync command: {output.decode("utf-8")}')
output = output.decode("utf-8").split('\n')
logger.info(f'rsync: {output[-3]}')
logger.info(f'rsync: {output[-2]}')
try:
os.symlink(self._output_dir, f'{self.output}/simple_backup/last_backup')
@ -223,7 +240,7 @@ def _parse_arguments():
epilog='Report bugs to dfucini<at>gmail<dot>com',
formatter_class=MyFormatter)
parser.add_argument('-c', '--config', default=f'{homedir}/.simple_backup/simple_backup.config',
parser.add_argument('-c', '--config', default=f'{homedir}/.config/simple_backup/simple_backup.config',
help='Specify location of configuration file')
parser.add_argument('-i', '--input', nargs='+', help='Paths/files to backup')
parser.add_argument('-o', '--output', help='Output directory for the backup')
@ -277,6 +294,8 @@ def simple_backup():
else:
backup_options = '-arvh -H -X'
output = os.path.abspath(output)
backup = Backup(inputs, output, exclude, keep, backup_options)
if backup.check_params():