Initial mysync implementation
This commit is contained in:
parent
727495386e
commit
81f7cf4b2e
14
example/backup_config.py
Normal file
14
example/backup_config.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
backup = True
|
||||||
|
backup_basepath = '/data/backup/ahorn'
|
||||||
|
|
||||||
|
installations = ['mint', 'kubuntu', 'openSuSE']
|
||||||
|
for installation in installations:
|
||||||
|
setattr(sys.modules[__name__], 'home_%s_remotepath' % installation, 'dirk@ahorn:/home')
|
||||||
|
setattr(sys.modules[__name__], 'home_%s_localpath' % installation, os.path.join(installation, 'home'))
|
||||||
|
|
||||||
|
user_data_remotepath = 'dirk@ahorn:/user_data'
|
||||||
|
user_data_localpath = 'user_data'
|
||||||
|
user_data_skip = ['static_data']
|
25
example/sync_config.py
Normal file
25
example/sync_config.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
backup = False
|
||||||
|
|
||||||
|
hosts = ['ahorn', 'erle', 'linde']
|
||||||
|
__basepath__ = '/user_data'
|
||||||
|
entries = (
|
||||||
|
('dirk@%s:/user_data/bin', os.path.join(__basepath__, 'bin'), None),
|
||||||
|
('dirk@%s:/user_data/data', os.path.join(__basepath__, 'data'), None),
|
||||||
|
('dirk@%s:/user_data/static_data', os.path.join(__basepath__, 'static_data'), ['Audio', 'timeshift', 'lost+found']),
|
||||||
|
('dirk@%s:/home', '/home', None),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
for host in hosts:
|
||||||
|
for remote, local, skip in entries:
|
||||||
|
setattr(sys.modules[__name__], host + '_' + os.path.basename(local) + '_remotepath', remote % host)
|
||||||
|
setattr(sys.modules[__name__], host + '_' + os.path.basename(local) + '_localpath', local)
|
||||||
|
if skip is not None:
|
||||||
|
setattr(sys.modules[__name__], host + '_' + os.path.basename(local) + '_skip', skip)
|
||||||
|
|
||||||
|
|
||||||
|
mount_mockery_audio_remotepath = 'root@mount-mockery.de:/data/audio/items'
|
||||||
|
mount_mockery_audio_localpath = os.path.join(__basepath__, 'static_data', 'dirk', 'Audio')
|
137
mysync
Executable file
137
mysync
Executable file
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
import config
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
RSYNC_REMOTE_COMMAND = 'sudo rsync'
|
||||||
|
TIME_FORMAT = "%Y-%m-%d_%H-%M-%S"
|
||||||
|
try:
|
||||||
|
basepath = config.backup_basepath
|
||||||
|
except AttributeError:
|
||||||
|
basepath = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
timestamp = time.strftime(TIME_FORMAT)
|
||||||
|
output_lines = 5
|
||||||
|
|
||||||
|
PROP_REMOTE = 'remotepath'
|
||||||
|
PROP_LOCAL = 'localpath'
|
||||||
|
PROP_SKIP = 'skip'
|
||||||
|
|
||||||
|
|
||||||
|
HEADER = '\033[95m'
|
||||||
|
OKBLUE = '\033[94m'
|
||||||
|
OKGREEN = '\033[92m'
|
||||||
|
WARNING = '\033[93m'
|
||||||
|
FAIL = '\033[91m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
CLEAR_REST_OF_LINE = '\033[K'
|
||||||
|
|
||||||
|
|
||||||
|
def status_line(line):
|
||||||
|
sys.stdout.write('\r .....' + line.replace('\n', '')[-60:] + CLEAR_REST_OF_LINE)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def parse_config_to_dict():
|
||||||
|
d = {}
|
||||||
|
config_dict = dir(config)
|
||||||
|
for key in config_dict:
|
||||||
|
if key.endswith('_' + PROP_REMOTE):
|
||||||
|
entry_name = key[:-len(PROP_REMOTE) - 1]
|
||||||
|
if entry_name + '_' + PROP_LOCAL in config_dict:
|
||||||
|
d[entry_name] = {}
|
||||||
|
for key in config_dict:
|
||||||
|
if key.startswith(entry_name):
|
||||||
|
d[entry_name][key[key.rfind('_') + 1:]] = getattr(config, key)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def rsync_command(**kwargs):
|
||||||
|
def path_filter(path):
|
||||||
|
return path if path.endswith('/') else path + '/'
|
||||||
|
#
|
||||||
|
if config.backup:
|
||||||
|
localpath = path_filter(os.path.join(basepath, timestamp, kwargs[PROP_LOCAL]))
|
||||||
|
if timestamp not in localpath:
|
||||||
|
sys.stderr.write('Unable to backup to %s. Please give a relative path for a backup!\n' % localpath)
|
||||||
|
localpath = None
|
||||||
|
else:
|
||||||
|
localpath = path_filter(os.path.join(basepath, kwargs.get('localpath', '')))
|
||||||
|
if localpath is not None:
|
||||||
|
remotepath = path_filter(kwargs.get(PROP_REMOTE))
|
||||||
|
skip = kwargs.get(PROP_SKIP)
|
||||||
|
cmd_l = ['rsync', '-avn' if DEBUG else '-av', '--delete', '--rsync-path="%s"' % RSYNC_REMOTE_COMMAND, remotepath, localpath]
|
||||||
|
if skip is not None:
|
||||||
|
cmd_l.append('--exclude=%s' % ','.join(skip))
|
||||||
|
if not os.path.exists(localpath):
|
||||||
|
return 'mkdir -p %s && ' % localpath + ' '.join(cmd_l)
|
||||||
|
return ' '.join(cmd_l)
|
||||||
|
|
||||||
|
|
||||||
|
def link_copy_command():
|
||||||
|
newest_backup = None
|
||||||
|
if not os.path.exists(basepath):
|
||||||
|
os.system('mkdir -p ' + basepath)
|
||||||
|
for path in os.listdir(basepath):
|
||||||
|
try:
|
||||||
|
t = time.strptime(path, TIME_FORMAT)
|
||||||
|
if newest_backup is None or t > newest_backup:
|
||||||
|
newest_backup = t
|
||||||
|
except ValueError:
|
||||||
|
pass # seems to be not one of my backups
|
||||||
|
if newest_backup is not None:
|
||||||
|
newest_backup = os.path.join(basepath, time.strftime(TIME_FORMAT, newest_backup))
|
||||||
|
return 'cp -alv ' + newest_backup + ' ' + os.path.join(basepath, timestamp)
|
||||||
|
|
||||||
|
|
||||||
|
def help_msg():
|
||||||
|
backup_dict = parse_config_to_dict()
|
||||||
|
print("Possible arguments are:")
|
||||||
|
for entry in backup_dict:
|
||||||
|
print(" * %s (%s -> %s)" % (entry + (20 - len(entry)) * ' ', backup_dict[entry][PROP_REMOTE] + (40 - len(backup_dict[entry][PROP_REMOTE])) * ' ', backup_dict[entry][PROP_LOCAL] + (40 - len(backup_dict[entry][PROP_LOCAL])) * ' '))
|
||||||
|
|
||||||
|
def make_link_copy():
|
||||||
|
cmd = link_copy_command()
|
||||||
|
if cmd is not None:
|
||||||
|
sys.stdout.write(BOLD + HEADER + UNDERLINE + 'Creating Link copy of last backup.' + ENDC + '\n\n')
|
||||||
|
with subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
|
||||||
|
err = b""
|
||||||
|
for line in p.stdout:
|
||||||
|
status_line(line.decode('utf-8'))
|
||||||
|
err += p.stderr.read()
|
||||||
|
sys.stdout.write('\n' + FAIL + BOLD + err.decode('utf-8') + ENDC)
|
||||||
|
sys.stdout.write('\n' + 80 * '-' + '\n')
|
||||||
|
|
||||||
|
#
|
||||||
|
if __name__ == '__main__':
|
||||||
|
backup_dict = parse_config_to_dict()
|
||||||
|
#
|
||||||
|
backup_dict = parse_config_to_dict()
|
||||||
|
did_nothing = True
|
||||||
|
for entry in backup_dict:
|
||||||
|
if entry in sys.argv:
|
||||||
|
cmd = rsync_command(**backup_dict[entry])
|
||||||
|
if cmd is not None:
|
||||||
|
if config.backup and did_nothing:
|
||||||
|
make_link_copy()
|
||||||
|
did_nothing = False
|
||||||
|
sys.stdout.write(BOLD + HEADER + UNDERLINE + 'Doing %s for %s:' % ('backup' if config.backup else 'sync', repr(entry)) + ENDC + '\n\n')
|
||||||
|
with subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
|
||||||
|
err = b""
|
||||||
|
for line in p.stdout:
|
||||||
|
status_line(line.decode('utf-8'))
|
||||||
|
err += p.stderr.read()
|
||||||
|
sys.stdout.write('\n' + FAIL + BOLD + err.decode('utf-8') + ENDC)
|
||||||
|
sys.stdout.write('\n' + 80 * '-' + '\n')
|
||||||
|
if did_nothing:
|
||||||
|
help_msg()
|
||||||
|
else:
|
||||||
|
help_msg()
|
Loading…
x
Reference in New Issue
Block a user