28 Parse command-line arguments. |
28 Parse command-line arguments. |
29 """ |
29 """ |
30 |
30 |
31 parser = optparse.OptionParser( |
31 parser = optparse.OptionParser( |
32 prog = argv[0], |
32 prog = argv[0], |
33 usage = '%prog: [options] --source <src> --destination <dst>', |
33 usage = '%prog: [options] [ --config <path> | --target <path> [ --source <src> ] [ --interval <name> ] ]', |
34 |
34 |
35 # module docstring |
35 # module docstring |
36 # XXX: breaks multi-line descriptions.. |
36 # XXX: breaks multi-line descriptions.. |
37 description = __doc__, |
37 description = __doc__, |
38 ) |
38 ) |
72 |
72 |
73 # |
73 # |
74 parser.add_option('-c', '--config', metavar='FILE', |
74 parser.add_option('-c', '--config', metavar='FILE', |
75 help="Load configuration file") |
75 help="Load configuration file") |
76 |
76 |
77 |
|
78 # |
77 # |
79 parser.add_option('-s', '--source', metavar='RSYNC-PATH', |
78 parser.add_option('-T', '--target', metavar='PATH', |
80 help="Backup source in rsync-syntax") |
79 help="Target path") |
81 |
80 |
82 parser.add_option('-d', '--destination', metavar='RSYNC-PATH', |
81 parser.add_option('-s', '--source', metavar='RSYNC-PATH', dest='target_source', default=False, |
83 help="Backup destination in rsync-syntax") |
82 help="Run target backup from source in rsync-syntax") |
84 |
83 |
85 parser.add_option('--interval', metavar='NAME', action='append', dest='target_intervals', |
84 parser.add_option('--interval', metavar='NAME', action='append', dest='target_intervals', |
86 help="Enable given interval") |
85 help="Run target with given given interval(s)") |
87 |
86 |
88 |
87 |
89 # defaults |
88 # defaults |
90 parser.set_defaults( |
89 parser.set_defaults( |
91 loglevel = logging.WARNING, |
90 loglevel = logging.WARNING, |
|
91 |
|
92 target_intervals = [], |
92 ) |
93 ) |
93 parser.set_defaults(**defaults) |
94 parser.set_defaults(**defaults) |
94 |
95 |
95 |
96 |
96 # parse |
97 # parse |
255 ) |
256 ) |
256 else : |
257 else : |
257 # partial instance with keep |
258 # partial instance with keep |
258 return cls(name, |
259 return cls(name, |
259 format = base.format, |
260 format = base.format, |
260 keep = config_int('keep', arg), |
261 keep = config_int('keep', arg) if arg else base.keep, |
261 ) |
262 ) |
262 |
263 |
263 def __init__ (self, name, format, keep) : |
264 def __init__ (self, name, format, keep) : |
264 self.name = name |
265 self.name = name |
265 self.format = format |
266 self.format = format |
336 self.snapshots_dir = os.path.join(self.path, 'snapshots') |
337 self.snapshots_dir = os.path.join(self.path, 'snapshots') |
337 |
338 |
338 # 'current' symlink |
339 # 'current' symlink |
339 self.current_path = os.path.join(self.path, 'current') |
340 self.current_path = os.path.join(self.path, 'current') |
340 |
341 |
341 def snapshot (self, options, now) : |
342 def prepare (self, options) : |
342 """ |
343 """ |
343 Perform the rsync from our source to self.snapshot_dir. |
344 Prepare dir for usage |
344 |
345 """ |
345 XXX: allocate snapshot_name here? |
346 |
346 """ |
347 if not os.path.exists(self.path) : |
|
348 raise Exception("Missing target dir: {path}".format(path=self.path)) |
347 |
349 |
348 if not os.path.exists(self.snapshots_dir) : |
350 if not os.path.exists(self.snapshots_dir) : |
349 log.warn("Creating snapshots dir: %s", self.snapshots_dir) |
351 log.warn("Creating snapshots dir: %s", self.snapshots_dir) |
350 os.mkdir(self.snapshots_dir) |
352 os.mkdir(self.snapshots_dir) |
351 |
353 |
|
354 def snapshot (self, options, now) : |
|
355 """ |
|
356 Perform the rsync from our source to self.snapshot_dir. |
|
357 |
|
358 XXX: allocate snapshot_name here? |
|
359 """ |
|
360 |
352 # new snapshot |
361 # new snapshot |
353 snapshot_name = now.strftime(options.snapshot_format) |
362 snapshot_name = now.strftime(options.snapshot_format) |
354 snapshot_path = os.path.join(self.snapshots_dir, snapshot_name) |
363 snapshot_path = os.path.join(self.snapshots_dir, snapshot_name) |
355 temp_path = os.path.join(self.snapshots_dir, 'tmp') |
364 temp_path = os.path.join(self.snapshots_dir, 'tmp') |
356 |
365 |
572 def run (self, options) : |
581 def run (self, options) : |
573 """ |
582 """ |
574 Execute |
583 Execute |
575 """ |
584 """ |
576 |
585 |
|
586 # prep |
|
587 self.prepare(options) |
|
588 |
577 # clean intervals? |
589 # clean intervals? |
578 if options.clean_intervals: |
590 if options.clean_intervals: |
579 for interval in self.intervals : |
591 for interval in self.intervals : |
580 log.info("Cleaning interval: %s...", interval) |
592 log.info("Cleaning interval: %s...", interval) |
581 |
593 |
617 if options.config : |
629 if options.config : |
618 # load |
630 # load |
619 config = parse_config(options.config, config) |
631 config = parse_config(options.config, config) |
620 |
632 |
621 # manual? |
633 # manual? |
622 if options.destination : |
634 if options.target : |
623 config['targets']['<commandline>'] = dict( |
635 config['targets'][options.target] = dict( |
624 path = options.destination, |
636 path = options.target, |
625 source = options.source, |
637 source = options.target_source, |
626 intervals = options.target_intervals, |
638 intervals = dict((name, None) for name in options.target_intervals), |
627 ) |
639 ) |
628 |
640 |
629 # intervals |
641 # intervals |
630 for name in config['intervals'] : |
642 for name in config['intervals'] : |
631 interval_config = config['intervals'][name] |
643 interval_config = config['intervals'][name] |
647 log.debug("rsync option: %s=%s", option, value) |
659 log.debug("rsync option: %s=%s", option, value) |
648 |
660 |
649 # store |
661 # store |
650 options.rsync_options[option] = value |
662 options.rsync_options[option] = value |
651 |
663 |
652 for name in config['targets'] : |
664 # all targets? |
|
665 if not targets : |
|
666 targets = list(config['targets']) |
|
667 |
|
668 # targets |
|
669 for name in targets : |
653 target_config = config['targets'][name] |
670 target_config = config['targets'][name] |
654 |
671 |
655 # parse |
672 # parse |
656 target = Target.from_config(options, name, **target_config) |
673 target = Target.from_config(options, name, **target_config) |
657 |
674 |
710 defaults = config_defaults() |
727 defaults = config_defaults() |
711 |
728 |
712 # global options + args |
729 # global options + args |
713 options, args = parse_options(argv, defaults) |
730 options, args = parse_options(argv, defaults) |
714 |
731 |
715 # XXX: args? |
732 # args: filter targets |
716 if args : |
733 # XXX: fix name mangling |
717 log.error("No arguments are handled") |
734 targets = [target.replace('-', '_') for target in args] |
718 return 2 |
|
719 |
735 |
720 try : |
736 try : |
721 # handle it |
737 # handle it |
722 return run(options) |
738 return run(options, targets) |
723 |
739 |
724 except Exception, e: |
740 except Exception, e: |
725 log.error("Internal error:", exc_info=e) |
741 log.error("Internal error:", exc_info=e) |
726 return 3 |
742 return 3 |
727 |
743 |