Alexey Golubev | 6f55d7e | 2016-03-23 16:16:29 +0300 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- |
| 3 | |
| 4 | import os |
| 5 | import sys |
| 6 | import logging |
| 7 | from cliff.app import App |
| 8 | from cliff.commandmanager import CommandManager |
| 9 | from cliff.command import Command |
| 10 | |
| 11 | from trsync.objects.rsync_mirror import TRsync |
| 12 | |
| 13 | class PushCmd(Command): |
| 14 | log = logging.getLogger(__name__) |
| 15 | |
| 16 | def get_description(self): |
| 17 | return "push SRC to several DST with snapshots" |
| 18 | |
| 19 | def get_parser(self, prog_name): |
| 20 | parser = super(PushCmd, self).get_parser(prog_name) |
| 21 | parser.add_argument('source', help='Source path') |
| 22 | parser.add_argument('mirror_name', help='Mirror name') |
| 23 | parser.add_argument('-d', '--dest', |
| 24 | nargs='+', |
| 25 | required=True, |
| 26 | help='Destination rsync url') |
| 27 | parser.add_argument('-t', '--timestamp', |
| 28 | required=False, |
| 29 | help='Specified timestamp will be used for snapshot.' |
| 30 | 'Format:yyyy-mm-dd-hhMMSS') |
| 31 | parser.add_argument('--snapshot-dir', |
| 32 | required=False, |
| 33 | default='snapshots', |
| 34 | help='Directory name for snapshots. "snapshots" ' |
| 35 | 'by default') |
| 36 | parser.add_argument('--init-directory-structure', |
| 37 | action='store_true', |
| 38 | required=False, |
| 39 | default=False, |
| 40 | help='It specified, all directories including' |
| 41 | '"snapshots-dir" will be created on remote location') |
| 42 | parser.add_argument('--save-latest-days', |
| 43 | required=False, |
| 44 | default=61, |
| 45 | help='Snapshots for specified number of days will be ' |
| 46 | 'saved. All older will be removed. 61 by default. ' |
| 47 | '0 mean that old snapshots will not be deleted, ' |
| 48 | '"None" mean that all snapshots excluding latest ' |
| 49 | 'will be deleted') |
| 50 | parser.add_argument('--latest-successful-postfix', |
| 51 | required=False, |
| 52 | default='latest', |
| 53 | help='Postfix for symlink to latest successfully ' |
| 54 | 'synced snapshot. Also used as --link-dest target. ' |
| 55 | '"latest" by default.') |
| 56 | parser.add_argument('-s', '--symlinks', |
| 57 | nargs='+', |
| 58 | required=False, |
| 59 | default=[], |
| 60 | help='Update additional symlinks relative destination') |
| 61 | parser.add_argument('--extra', |
| 62 | required=False, |
| 63 | default='', |
| 64 | #action='store_const', |
| 65 | help='String with additional rsync parameters. For ' |
| 66 | 'example it may be "\--dry-run --any-rsync-option".' |
| 67 | 'Use "\\" to disable argparse to parse extra value.') |
| 68 | |
| 69 | return parser |
| 70 | |
| 71 | def take_action(self, parsed_args): |
| 72 | properties = vars(parsed_args) |
| 73 | source_dir = properties.pop('source', None) |
| 74 | mirror_name = properties.pop('mirror_name', None) |
| 75 | symlinks = properties.pop('symlinks', None) |
| 76 | servers = properties.pop('dest', None) |
| 77 | if properties['extra'].startswith('\\'): |
| 78 | properties['extra'] = properties['extra'][1:] |
| 79 | properties['rsync_extra_params'] = properties.pop('extra') |
| 80 | properties['save_latest_days'] = \ |
| 81 | None if properties['save_latest_days'] == 'None' \ |
| 82 | else int(properties['save_latest_days']) |
| 83 | |
| 84 | failed = list() |
| 85 | for server in servers: |
| 86 | source_dir = os.path.realpath(source_dir) |
| 87 | if not source_dir.endswith('/'): |
| 88 | source_dir += '/' |
| 89 | remote = TRsync(server, **properties) |
| 90 | try: |
| 91 | remote.push(source_dir, mirror_name, symlinks=symlinks) |
| 92 | except Exception as e: |
| 93 | print e.message |
| 94 | failed.append(server) |
| 95 | |
| 96 | if failed: |
| 97 | print "Failed to push to {}".format(str(failed)) |
| 98 | sys.exit(1) |
| 99 | #self.app.stdout.write(parsed_args.arg + "\n") |
| 100 | |
| 101 | class RemoveCmd(Command): |
| 102 | log = logging.getLogger(__name__) |
| 103 | |
| 104 | def get_description(self): |
| 105 | return "remove all specified paths from several DST recursively" |
| 106 | |
| 107 | def get_parser(self, prog_name): |
| 108 | parser = super(RemoveCmd, self).get_parser(prog_name) |
| 109 | |
| 110 | parser.add_argument('path', |
| 111 | nargs='+', |
| 112 | help='Path to remove') |
| 113 | parser.add_argument('-d', '--dest', |
| 114 | nargs='+', |
| 115 | required=True, |
| 116 | help='Destination rsync url') |
| 117 | parser.add_argument('--extra', |
| 118 | required=False, |
| 119 | default='', |
| 120 | help='String with additional rsync parameters. For ' |
| 121 | 'example it may be "\--dry-run --any-rsync-option".' |
| 122 | 'Use "\\" to disable argparse to parse extra value.') |
| 123 | return parser |
| 124 | |
| 125 | def take_action(self, parsed_args): |
| 126 | properties = vars(parsed_args) |
| 127 | servers = properties.pop('dest', None) |
| 128 | path = properties.pop('path', None) |
| 129 | if properties['extra'].startswith('\\'): |
| 130 | properties['extra'] = properties['extra'][1:] |
| 131 | properties['init_directory_structure'] = False |
| 132 | properties['rsync_extra_params'] = properties.pop('extra')# + ' --dry-run' |
| 133 | |
| 134 | failed = list() |
| 135 | for server in servers: |
| 136 | remote = TRsync(server, **properties) |
| 137 | try: |
| 138 | print "Removing items {}".format(str(path)) |
| 139 | remote.rm_all(path) |
| 140 | except Exception as e: |
| 141 | print e.message |
| 142 | failed.append(server) |
| 143 | |
| 144 | if failed: |
| 145 | print "Failed to remove {}".format(str(failed)) |
| 146 | sys.exit(1) |
| 147 | |
| 148 | class TRsyncApp(App): |
| 149 | log = logging.getLogger(__name__) |
| 150 | |
| 151 | def __init__(self): |
| 152 | super(TRsyncApp, self).__init__( |
| 153 | description='TRsync', |
| 154 | version=trsync.__version__, |
| 155 | command_manager=CommandManager('trsync'), |
| 156 | deferred_help=True, |
| 157 | ) |
| 158 | |
| 159 | def main(argv=sys.argv[1:]): |
| 160 | app = TRsyncApp() |
| 161 | return app.run(argv) |
| 162 | |
| 163 | if __name__ == '__main__': |
| 164 | sys.exit(main(sys.argv[1:])) |