Initial commit
This commit is contained in:
commit
996da02e01
|
@ -0,0 +1,43 @@
|
|||
import os
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
from ..src import backup_manager
|
||||
|
||||
CONFIG_FILE_LIST = [
|
||||
'.backup-client.cfg',
|
||||
'~/.backup-client.cfg',
|
||||
'/etc/backup-client.cfg',
|
||||
]
|
||||
|
||||
manager_impl_dict = {
|
||||
'rsync': backup_manager.RsyncBackupManager,
|
||||
'rdiff-backup': backup_manager.RdiffBackupManager,
|
||||
}
|
||||
|
||||
def main():
|
||||
for filename in CONFIG_FILE_LIST:
|
||||
if os.path.exists(filename):
|
||||
with open(filename) as f:
|
||||
config = yaml.load(f.read())
|
||||
break
|
||||
else:
|
||||
print('No configuration file found')
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
backup_manager = manager_impl_dict[config['copy_tool']](
|
||||
config['copy_tool'],
|
||||
config['path_list'],
|
||||
config['remote_path'],
|
||||
config.get('extra_args', []),
|
||||
config.get('dry_run', False),
|
||||
)
|
||||
except KeyError as e:
|
||||
print('Option %s not found in configuration file %s' % (e, filename))
|
||||
sys.exit(1)
|
||||
except AttributeError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
backup_manager.start()
|
|
@ -0,0 +1,77 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
class BackupManager:
|
||||
def __init__(self, copy_binary, path_list, remote_path, extra_args, dry_run):
|
||||
self.copy_binary = copy_binary
|
||||
self.remote_path = remote_path
|
||||
self.extra_args = extra_args
|
||||
self.dry_run = dry_run
|
||||
self.path_list = []
|
||||
|
||||
for path in path_list:
|
||||
path = os.path.abspath(
|
||||
os.path.expanduser(
|
||||
os.path.expandvars(path)))
|
||||
if not os.path.exists(path):
|
||||
raise AttributeError('Path %s doesn\'t exist' % path)
|
||||
self.path_list.append(path)
|
||||
|
||||
|
||||
def _build_command_list(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def start(self):
|
||||
command_list = self._build_command_list()
|
||||
for command in command_list:
|
||||
print('Running : %s' % ' '.join(command))
|
||||
subprocess.call(
|
||||
command,
|
||||
stdout=sys.stdout,
|
||||
)
|
||||
|
||||
|
||||
class RsyncBackupManager(BackupManager):
|
||||
|
||||
def _build_command_list(self):
|
||||
command_list = []
|
||||
hostname = os.uname().nodename
|
||||
short_option_list = '-az'
|
||||
|
||||
if self.dry_run:
|
||||
short_option_list += 'n'
|
||||
|
||||
for path in self.path_list:
|
||||
command_list.append((
|
||||
self.copy_binary,
|
||||
short_option_list,
|
||||
'--relative',
|
||||
*self.extra_args,
|
||||
path,
|
||||
self.remote_path + '/' + hostname,
|
||||
))
|
||||
|
||||
return command_list
|
||||
|
||||
|
||||
class RdiffBackupManager(BackupManager):
|
||||
|
||||
def _build_command_list(self):
|
||||
command_list = []
|
||||
hostname = os.uname().nodename
|
||||
|
||||
if self.dry_run:
|
||||
self.extra_args.append('--compare-hash')
|
||||
|
||||
for path in self.path_list:
|
||||
command_list.append((
|
||||
self.copy_binary,
|
||||
'--create-full-path',
|
||||
*self.extra_args,
|
||||
path,
|
||||
self.remote_path + '/' + hostname,
|
||||
))
|
||||
|
||||
return command_list
|
|
@ -0,0 +1 @@
|
|||
pyyaml
|
|
@ -0,0 +1,22 @@
|
|||
# Tool used for backuping files.
|
||||
# Supported values are 'rsync' and 'rdiff-backup'
|
||||
copy_tool: 'rsync'
|
||||
|
||||
# Destination where the files will be sent.
|
||||
# It can be a remote schema, or a local path.
|
||||
# remote_path: '/tmp'
|
||||
remote_path: 'backup@example.com:~'
|
||||
|
||||
# Extra argument to pass to the backup command.
|
||||
# See the man of rsync/rdiff-backup for knowing
|
||||
# which options are supported
|
||||
#extra_args:
|
||||
# - -e
|
||||
# - ssh -p 2222
|
||||
|
||||
# List of local directories/files to backup
|
||||
path_list:
|
||||
- /home/user/
|
||||
|
||||
# Dry run
|
||||
#dry_run: true
|
|
@ -0,0 +1,27 @@
|
|||
import os
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
# Utility function to read the README file.
|
||||
# Used for the long_description. It's nice, because now 1) we have a top level
|
||||
# README file and 2) it's easier to type in the README file than to put a raw
|
||||
# string in below ...
|
||||
def read(fname):
|
||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||
|
||||
setup(
|
||||
name = "backupclient",
|
||||
version = "0.1",
|
||||
packages = find_packages(),
|
||||
author = "Nicolas Wavrant",
|
||||
author_email = "nicolas.wavrant@gmail.com",
|
||||
description = ("A backup client command. It is a wrapper over rsync and rdiff-backup with a config file parser, to automate backups."),
|
||||
license = "BSD",
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'backupclient=backupclient.bin.backupclient:main',
|
||||
],
|
||||
},
|
||||
install_requires = [
|
||||
'pyyaml',
|
||||
],
|
||||
)
|
Loading…
Reference in New Issue