13 from pvl.backup import __version__ |
13 from pvl.backup import __version__ |
14 from pvl.backup import rsync, invoke |
14 from pvl.backup import rsync, invoke |
15 |
15 |
16 import optparse, ConfigParser |
16 import optparse, ConfigParser |
17 import os, os.path, stat |
17 import os, os.path, stat |
18 import shutil |
18 import shutil, glob |
19 import datetime |
19 import datetime |
20 import logging |
20 import logging |
21 |
21 |
22 log = logging.getLogger() |
22 log = logging.getLogger() |
23 |
23 |
71 |
71 |
72 parser.add_option('-n', '--dry-run', action='store_true', |
72 parser.add_option('-n', '--dry-run', action='store_true', |
73 help="Don't actually clean anything") |
73 help="Don't actually clean anything") |
74 |
74 |
75 # |
75 # |
76 parser.add_option('-c', '--config', metavar='FILE', |
76 parser.add_option('-c', '--config', metavar='FILE/DIR', action='append', # multi |
77 help="Load configuration file") |
77 help="Load configuration file(s)") |
78 |
78 |
79 parser.add_option('-r', '--run', metavar='NAME', |
79 parser.add_option('-r', '--run', metavar='NAME', |
80 help="Run given set of targets, per config [run/...]") |
80 help="Run given set of targets, per config [run/...]") |
81 |
81 |
82 # |
82 # |
130 |
131 |
131 return name.replace('-', '_') |
132 return name.replace('-', '_') |
132 |
133 |
133 def parse_config (path, defaults) : |
134 def parse_config (path, defaults) : |
134 """ |
135 """ |
135 Parse given config file |
136 Parse given config file, returning updated set of configs based on given defaults. |
136 """ |
137 """ |
137 |
138 |
138 log.debug("loading config: %s", path) |
139 log.debug("loading config: %s", path) |
139 |
140 |
140 config = dict(defaults) |
141 config = dict(defaults) |
699 if target not in options.targets : |
700 if target not in options.targets : |
700 raise ConfigError("Unknown [target/{target}] in [run/{run}]".format(target=target, run=run)) |
701 raise ConfigError("Unknown [target/{target}] in [run/{run}]".format(target=target, run=run)) |
701 |
702 |
702 yield target |
703 yield target |
703 |
704 |
|
705 def load_configs (configs, confglob='*.conf') : |
|
706 """ |
|
707 Load configuration files from given list of config paths; supports loading a conf.d |
|
708 """ |
|
709 |
|
710 for path in configs : |
|
711 log.debug("%s", path) |
|
712 |
|
713 if os.path.isdir(path) : |
|
714 # glob dir: $path/$glob |
|
715 for globpath in glob.glob(os.path.join(path, confglob)) : |
|
716 if os.path.exists(globpath) : |
|
717 yield globpath |
|
718 else : |
|
719 raise Exception("Globbed file does not exist: {0}".format(globpath)) |
|
720 |
|
721 elif os.path.isfile(path) : |
|
722 # normal file |
|
723 yield path |
|
724 |
|
725 elif os.path.exists(path) : |
|
726 raise Exception("Unrecognized config file type: {0}".format(path)) |
|
727 |
|
728 else : |
|
729 raise Exception("Given config file does not exist: {0}".format(path)) |
|
730 |
704 def run (options, run_targets) : |
731 def run (options, run_targets) : |
705 # default config |
732 # default config |
706 config = dict( |
733 config = dict( |
707 rsync_options = {}, |
734 rsync_options = {}, |
708 intervals = {}, |
735 intervals = {}, |
709 targets = {}, |
736 targets = {}, |
710 ) |
737 ) |
711 |
738 |
712 if options.config : |
739 # config? |
|
740 for path in load_configs(options.config) : |
713 # load |
741 # load |
714 try : |
742 try : |
715 config = parse_config(options.config, config) |
743 config = parse_config(path, config) |
716 except ConfigError as e: |
744 except ConfigError as e: |
717 log.error("Configuration error: %s: %s", options.config, e) |
745 log.error("Configuration error: %s: %s", path, e) |
718 return 2 |
746 return 2 |
719 |
747 |
720 # targets to run |
748 # targets to run |
721 options.targets = {} |
749 options.targets = {} |
722 |
750 |