borgmatic.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from argparse import ArgumentParser
  2. import os
  3. from subprocess import CalledProcessError
  4. import sys
  5. from borgmatic.borg import check, create, prune
  6. from borgmatic.config import collect, convert, validate
  7. LEGACY_CONFIG_PATH = '/etc/borgmatic/config'
  8. def parse_arguments(*arguments):
  9. '''
  10. Given command-line arguments with which this script was invoked, parse the arguments and return
  11. them as an ArgumentParser instance.
  12. '''
  13. parser = ArgumentParser(
  14. description=
  15. '''
  16. A simple wrapper script for the Borg backup software that creates and prunes backups.
  17. If none of the --prune, --create, or --check options are given, then borgmatic defaults
  18. to all three: prune, create, and check archives.
  19. '''
  20. )
  21. parser.add_argument(
  22. '-c', '--config',
  23. nargs='+',
  24. dest='config_paths',
  25. default=collect.DEFAULT_CONFIG_PATHS,
  26. help='Configuration filenames or directories, defaults to: {}'.format(' '.join(collect.DEFAULT_CONFIG_PATHS)),
  27. )
  28. parser.add_argument(
  29. '--excludes',
  30. dest='excludes_filename',
  31. help='Deprecated in favor of exclude_patterns within configuration',
  32. )
  33. parser.add_argument(
  34. '-p', '--prune',
  35. dest='prune',
  36. action='store_true',
  37. help='Prune archives according to the retention policy',
  38. )
  39. parser.add_argument(
  40. '-C', '--create',
  41. dest='create',
  42. action='store_true',
  43. help='Create archives (actually perform backups)',
  44. )
  45. parser.add_argument(
  46. '-k', '--check',
  47. dest='check',
  48. action='store_true',
  49. help='Check archives for consistency',
  50. )
  51. parser.add_argument(
  52. '-v', '--verbosity',
  53. type=int,
  54. help='Display verbose progress (1 for some, 2 for lots)',
  55. )
  56. args = parser.parse_args(arguments)
  57. # If any of the three action flags in the given parse arguments have been explicitly requested,
  58. # leave them as-is. Otherwise, assume defaults: Mutate the given arguments to enable all the
  59. # actions.
  60. if not args.prune and not args.create and not args.check:
  61. args.prune = True
  62. args.create = True
  63. args.check = True
  64. return args
  65. def main(): # pragma: no cover
  66. try:
  67. args = parse_arguments(*sys.argv[1:])
  68. config_filenames = tuple(collect.collect_config_filenames(args.config_paths))
  69. convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)
  70. if len(config_filenames) == 0:
  71. raise ValueError('Error: No configuration files found in: {}'.format(' '.join(args.config_paths)))
  72. for config_filename in config_filenames:
  73. config = validate.parse_configuration(config_filename, validate.schema_filename())
  74. (location, storage, retention, consistency) = (
  75. config.get(section_name, {})
  76. for section_name in ('location', 'storage', 'retention', 'consistency')
  77. )
  78. remote_path = location.get('remote_path')
  79. create.initialize(storage)
  80. for repository in location['repositories']:
  81. if args.prune:
  82. prune.prune_archives(args.verbosity, repository, retention, remote_path=remote_path)
  83. if args.create:
  84. create.create_archive(
  85. args.verbosity,
  86. repository,
  87. location,
  88. storage,
  89. )
  90. if args.check:
  91. check.check_archives(args.verbosity, repository, consistency, remote_path=remote_path)
  92. except (ValueError, OSError, CalledProcessError) as error:
  93. print(error, file=sys.stderr)
  94. sys.exit(1)