|
|
@@ -0,0 +1,157 @@ |
|
|
|
|
|
#!/usr/bin/env python |
|
|
# |
|
|
# Additional wrapper to ``rsync`` command with profiles. |
|
|
# |
|
|
# Requirements |
|
|
# ============ |
|
|
# |
|
|
# * Python_ 2.4 or higher |
|
|
# * rsync_ |
|
|
# |
|
|
# .. _Python: http://www.python.org/ |
|
|
# .. _rsync: http://rsync.samba.org/ |
|
|
# |
|
|
# Installation |
|
|
# ============ |
|
|
# |
|
|
# Place ``sync-it.py`` somewhere in your ``$PATH`` and give to it necessary |
|
|
# permissions (``$ chmod +x``). |
|
|
# |
|
|
# Then create config file with default options to rsync and profiles to sync |
|
|
# and store it on ``~/.config/sync-it/sync-it.conf``. |
|
|
# |
|
|
# Usage |
|
|
# ===== |
|
|
# |
|
|
# $ sync-it [-i] [-o options] profile |
|
|
# |
|
|
# Example of configuration file |
|
|
# ============================= |
|
|
# |
|
|
# :: |
|
|
# |
|
|
# # You cannot use "rsync" as profile name. But, this block is not |
|
|
# # required. |
|
|
# [rsync] |
|
|
# options = --progress -lzuogthvr --compress-level=9 |
|
|
# |
|
|
# [profile] |
|
|
# src = rsync://server/path/to/src/ |
|
|
# dest = /path/to/dest/ |
|
|
# |
|
|
# [other_profile] |
|
|
# options = -avz # You should redefine rsync options for each profile |
|
|
# src = rsync://server/path/to/other_src/ |
|
|
# dest = ~/path/to/other_dest/ # You should use tilda in profile pathes |
|
|
# |
|
|
|
|
|
import os |
|
|
import sys |
|
|
|
|
|
from ConfigParser import ConfigParser, Error as ConfigParserError |
|
|
from optparse import OptionParser |
|
|
from subprocess import Popen |
|
|
|
|
|
|
|
|
# Application settings |
|
|
__usage__ = 'Usage: %prog [-i] [-o options] profile' |
|
|
__version__ = '0.1-alpha' |
|
|
|
|
|
# Necessary global vars |
|
|
RSYNC = 'rsync' |
|
|
|
|
|
|
|
|
def get_options(): |
|
|
""" |
|
|
Build option parser, read profile from arguments passed to script then try |
|
|
to read configuration for this profile and return configuration as |
|
|
``dict`` instance. |
|
|
""" |
|
|
# Build option parser and parse arguments passed to script |
|
|
parser = OptionParser(usage=__usage__, version=__version__) |
|
|
|
|
|
parser.add_option('-i', '--invert', action='store_true', dest='invert', |
|
|
default=False, help='Switch source and destination pathes for ' \ |
|
|
'selected profile.') |
|
|
parser.add_option('-o', '--options', dest='options', default='', |
|
|
help='Redefine global rsync options for selected profile.', |
|
|
metavar='OPTIONS') |
|
|
|
|
|
options, args = parser.parse_args() |
|
|
|
|
|
if not len(args): |
|
|
parser.error("You should pass 'profile' arg to the script.") |
|
|
|
|
|
profile = args[0] |
|
|
|
|
|
if profile == RSYNC: |
|
|
parser.error('%r is reserved system name and you cannot use it as ' \ |
|
|
'profile name.' % RSYNC) |
|
|
|
|
|
# Trying to read user configuration |
|
|
filename = os.path.expanduser('~/.config/sync-it/sync-it.conf') |
|
|
|
|
|
if not os.path.isfile(filename): |
|
|
parser.error('Cannot read configuration from %r. Please, create ' \ |
|
|
'configuration file there first.' % filename) |
|
|
|
|
|
config = ConfigParser() |
|
|
|
|
|
try: |
|
|
config.read(filename) |
|
|
except ConfigParserError: |
|
|
parser.error('Cannot parse configuration from %r. Please, check ' \ |
|
|
'syntax of your configuration file.' % filename) |
|
|
|
|
|
if not profile in config.sections(): |
|
|
parser.error('Cannot find %r section in your configuration file.' % \ |
|
|
profile) |
|
|
|
|
|
# User rsync options should used instead of profile rsync options |
|
|
if options.options: |
|
|
rsync_options = options.options |
|
|
# Profile rsync options should used instead of global rsync options |
|
|
if config.has_option(profile, 'options'): |
|
|
rsync_options = config.get(profile, 'options') |
|
|
elif config.has_option(RSYNC, 'options'): |
|
|
rsync_options = config.get(RSYNC, 'options') |
|
|
else: |
|
|
rsync_options = '' |
|
|
|
|
|
try: |
|
|
dest = os.path.expanduser(config.get(profile, 'dest')) |
|
|
src = os.path.expanduser(config.get(profile, 'src')) |
|
|
except ConfigParserError, e: |
|
|
parser.error(e) |
|
|
|
|
|
return {'dest': options.invert and src or dest, |
|
|
'options': rsync_options, |
|
|
'profile': profile, |
|
|
'src': options.invert and dest or src} |
|
|
|
|
|
|
|
|
def main(): |
|
|
# Read script options |
|
|
options = get_options() |
|
|
|
|
|
# Execute rsync for selected profile |
|
|
rsync(**options) |
|
|
|
|
|
|
|
|
def rsync(profile, src, dest, options): |
|
|
""" |
|
|
Wrapper to executing rsync command. |
|
|
""" |
|
|
cmd = ' '.join((RSYNC, options, src, dest)) |
|
|
print('$ ' + cmd) |
|
|
|
|
|
process = Popen(cmd, shell=True) |
|
|
status = os.waitpid(process.pid, 0)[1] |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
try: |
|
|
main() |
|
|
except KeyboardInterrupt: |
|
|
print('OK OK! Exiting immediately...') |