backup.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import contextlib
  2. import os
  3. import yaml
  4. import sys
  5. from glob import glob
  6. @contextlib.contextmanager
  7. def pushd(newDir):
  8. previousDir = os.getcwd()
  9. os.chdir(newDir)
  10. try:
  11. yield
  12. finally:
  13. os.chdir(previousDir)
  14. class DependencyException(Exception):
  15. pass
  16. def deptree(sources, deps=None):
  17. if deps is None:
  18. deps = []
  19. deferred = []
  20. for name in sources.keys():
  21. source = sources[name]
  22. if "depends" not in source:
  23. deps.append(name)
  24. else:
  25. deferred.append(name)
  26. while deferred:
  27. name = deferred.pop()
  28. depends = sources[name]["depends"]
  29. # todo - detect dependency loop
  30. if name in depends:
  31. raise DependencyException('Source {} depends upon itself'.format(name))
  32. elif set(depends).issubset(set(deps)):
  33. deps.append(name)
  34. elif not set(depends).issubset(set(deps)):
  35. missing = ', '.join(set(depends).difference(set(deps)))
  36. raise DependencyException(
  37. 'Source {0} has missing dependencies: {1}'.format(name, missing))
  38. else:
  39. deferred.append(name)
  40. return deps
  41. def main(args):
  42. with pushd('etc/backup.d'):
  43. with open("backup.yml") as f:
  44. config = yaml.load(f)
  45. sources = {}
  46. for source in config['sources']:
  47. source = os.path.realpath(source)
  48. for path in glob('{}/*.yml'.format(source)):
  49. path = os.path.realpath(path)
  50. with pushd(os.path.dirname(path)), open(path) as f:
  51. data = yaml.load(f)
  52. if "depends" in data:
  53. for i in range(0, len(data["depends"])):
  54. data["depends"][i] = os.path.realpath(
  55. '{}.yml'.format(data["depends"][i]))
  56. sources[path] = data
  57. config['sources'] = sources
  58. import json
  59. for name in deptree(config["sources"]):
  60. source = config["sources"][name]
  61. print(json.dumps(source, indent=2))
  62. if __name__ == '__main__':
  63. try:
  64. main(sys.argv[1:])
  65. except DependencyException as ex:
  66. print(ex)
  67. sys.exit(1)
  68. except Exception:
  69. from traceback import format_exc
  70. msg = "Error encountered:\n" + format_exc().strip()
  71. print(msg)
  72. sys.exit(1)