|
@@ -1,17 +1,91 @@
|
|
|
+import contextlib
|
|
|
import os
|
|
|
-from glob import glob
|
|
|
import yaml
|
|
|
+import sys
|
|
|
+
|
|
|
+from glob import glob
|
|
|
+
|
|
|
[email protected]
|
|
|
+def pushd(newDir):
|
|
|
+ previousDir = os.getcwd()
|
|
|
+ os.chdir(newDir)
|
|
|
+ try:
|
|
|
+ yield
|
|
|
+
|
|
|
+ finally:
|
|
|
+ os.chdir(previousDir)
|
|
|
+
|
|
|
+class DependencyException(Exception):
|
|
|
+ pass
|
|
|
+
|
|
|
+def deptree(sources, deps=None):
|
|
|
+ if deps is None:
|
|
|
+ deps = []
|
|
|
+
|
|
|
+ deferred = []
|
|
|
+ for name in sources.keys():
|
|
|
+ source = sources[name]
|
|
|
+ if "depends" not in source:
|
|
|
+ deps.append(name)
|
|
|
+
|
|
|
+ else:
|
|
|
+ deferred.append(name)
|
|
|
+
|
|
|
+ while deferred:
|
|
|
+ name = deferred.pop()
|
|
|
+ depends = sources[name]["depends"]
|
|
|
+ # todo - detect dependency loop
|
|
|
+ if name in depends:
|
|
|
+ raise DependencyException('Source {} depends upon itself'.format(name))
|
|
|
+
|
|
|
+ elif set(depends).issubset(set(deps)):
|
|
|
+ deps.append(name)
|
|
|
+
|
|
|
+ elif not set(depends).issubset(set(deps)):
|
|
|
+ missing = ', '.join(set(depends).difference(set(deps)))
|
|
|
+ raise DependencyException(
|
|
|
+ 'Source {0} has missing dependencies: {1}'.format(name, missing))
|
|
|
+
|
|
|
+ else:
|
|
|
+ deferred.append(name)
|
|
|
+
|
|
|
+
|
|
|
+ return deps
|
|
|
+
|
|
|
+def main(args):
|
|
|
+ with pushd('etc/backup.d'):
|
|
|
+ with open("backup.yml") as f:
|
|
|
+ config = yaml.load(f)
|
|
|
+
|
|
|
+ sources = {}
|
|
|
+ for source in config['sources']:
|
|
|
+ source = os.path.realpath(source)
|
|
|
+ for path in glob('{}/*.yml'.format(source)):
|
|
|
+ path = os.path.realpath(path)
|
|
|
+ with pushd(os.path.dirname(path)), open(path) as f:
|
|
|
+ data = yaml.load(f)
|
|
|
+ if "depends" in data:
|
|
|
+ for i in range(0, len(data["depends"])):
|
|
|
+ data["depends"][i] = os.path.realpath('{}.yml'.format(data["depends"][i]))
|
|
|
+
|
|
|
+ sources[path] = data
|
|
|
+
|
|
|
+ config['sources'] = sources
|
|
|
+ import json
|
|
|
+ for name in deptree(config["sources"]):
|
|
|
+ source = config["sources"][name]
|
|
|
+ print(json.dumps(source, indent=2))
|
|
|
|
|
|
-with open("etc/backup.d/backup.yml") as f:
|
|
|
- config = yaml.load(f)
|
|
|
+if __name__ == '__main__':
|
|
|
+ try:
|
|
|
+ main(sys.argv[1:])
|
|
|
|
|
|
-sources = {}
|
|
|
-for source in config['sources']:
|
|
|
- for path in glob('etc/backup.d/{}/*.yml'.format(source)):
|
|
|
- with open(path) as f:
|
|
|
- if source not in sources:
|
|
|
- sources[source] = {}
|
|
|
- sources[source][os.path.basename(path)] = yaml.load(f)
|
|
|
+ except DependencyException as ex:
|
|
|
+ print(ex)
|
|
|
+ sys.exit(1)
|
|
|
|
|
|
-config['sources'] = sources
|
|
|
-print(config)
|
|
|
+ except Exception:
|
|
|
+ from traceback import format_exc
|
|
|
+ msg = "Error encountered:\n" + format_exc().strip()
|
|
|
+ print(msg)
|
|
|
+ sys.exit(1)
|