Upgrade configstuffs
Trying to add support for: - Multiple configs in one run - Multiple config path arguments - Allow a config path to be a directory of config files
This commit is contained in:
parent
918784bd00
commit
e5ea0dee9a
140
backup-rotator
140
backup-rotator
@ -12,16 +12,26 @@ class BackupRotator:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.__config = None
|
self.__dry_run = False
|
||||||
self.__config_path = None
|
self.__configs = []
|
||||||
|
self.__config_paths = []
|
||||||
|
self.__calculated_actions = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
self.log("Begin")
|
self.log("Begin")
|
||||||
self.consume_arguments()
|
self.consume_arguments()
|
||||||
self.consume_config(self.__config_path)
|
self.consume_configs(self.__config_paths)
|
||||||
|
|
||||||
self.rotate_paths()
|
# Rotate once per config
|
||||||
|
for config_index in range(len(self.__configs)):
|
||||||
|
|
||||||
|
#
|
||||||
|
config = self.__configs[config_index]
|
||||||
|
|
||||||
|
#
|
||||||
|
self.log("Rotating for config " + str(config_index + 1) + " of " + str(len(self.__configs)), config["__path"])
|
||||||
|
self.do_rotate(config)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def current_time():
|
def current_time():
|
||||||
@ -42,13 +52,20 @@ class BackupRotator:
|
|||||||
|
|
||||||
def consume_arguments(self):
|
def consume_arguments(self):
|
||||||
|
|
||||||
|
self.__config_paths = []
|
||||||
|
|
||||||
for i in range(1, len(sys.argv)):
|
for i in range(1, len(sys.argv)):
|
||||||
|
|
||||||
arg = sys.argv[i]
|
arg = sys.argv[i]
|
||||||
|
|
||||||
if arg == "--config":
|
if arg == "--config":
|
||||||
i, self.__config_path = self.consume_argument_companion(i)
|
i, one_path = self.consume_argument_companion(i)
|
||||||
print("Found config path:", self.__config_path)
|
self.__config_paths.append(one_path)
|
||||||
|
print("Found config path argument:", one_path)
|
||||||
|
|
||||||
|
elif arg == "--dry-run":
|
||||||
|
self.__dry_run = True
|
||||||
|
print("Activating global dry-run mode")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def consume_argument_companion(arg_index):
|
def consume_argument_companion(arg_index):
|
||||||
@ -59,34 +76,64 @@ class BackupRotator:
|
|||||||
|
|
||||||
return companion_index, sys.argv[companion_index]
|
return companion_index, sys.argv[companion_index]
|
||||||
|
|
||||||
def consume_config(self, path=None):
|
def consume_configs(self, paths: list=None):
|
||||||
|
|
||||||
if path is None:
|
if paths is None:
|
||||||
raise Exception("Auto-finding of config file not implemented")
|
raise Exception("Auto-finding of config file not implemented")
|
||||||
|
|
||||||
|
# Use each config path
|
||||||
|
for path in paths:
|
||||||
|
|
||||||
|
# If this is a single path
|
||||||
|
if os.path.isfile(path):
|
||||||
|
self.consume_config(path)
|
||||||
|
|
||||||
|
# If this is a directory
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
|
||||||
|
# Iterate over each file inside
|
||||||
|
for file_name in os.listdir(path):
|
||||||
|
self.consume_config(os.path.join(path, file_name))
|
||||||
|
|
||||||
|
def consume_config(self, path: str):
|
||||||
|
|
||||||
|
# Open the file
|
||||||
f = open(path)
|
f = open(path)
|
||||||
self.__config = yaml.load(f)
|
if not f:
|
||||||
|
raise Exception("Unable to open config file: " + path)
|
||||||
|
|
||||||
self.log("Consumed config from path: ", path)
|
# Parse
|
||||||
|
config = yaml.load(f)
|
||||||
def rotate_paths(self):
|
|
||||||
|
|
||||||
self.log("Begin rotating " + str(len(self.__config["paths"])) + " paths")
|
# Add its own path
|
||||||
for path in self.__config["paths"]:
|
config["__path"] = path
|
||||||
self.rotate_path(path)
|
|
||||||
|
# Consume to internal
|
||||||
|
self.__configs.append(config)
|
||||||
|
self.log("Consumed config from path:", path)
|
||||||
|
|
||||||
def rotate_path(self, path):
|
def do_rotate(self, config):
|
||||||
|
|
||||||
|
self.rotate_paths(config)
|
||||||
|
|
||||||
|
def rotate_paths(self, config):
|
||||||
|
|
||||||
|
self.log("Begin rotating " + str(len(config["paths"])) + " paths")
|
||||||
|
for path in config["paths"]:
|
||||||
|
self.rotate_path(config, path)
|
||||||
|
|
||||||
|
def rotate_path(self, config, path):
|
||||||
|
|
||||||
self.log("Rotating path", path)
|
self.log("Rotating path", path)
|
||||||
|
|
||||||
if "maximum-items" not in self.__config:
|
if "maximum-items" not in config:
|
||||||
raise Exception("Please provide config key: \"maximum-items\"")
|
raise Exception("Please provide config key: \"maximum-items\"")
|
||||||
max_items = self.__config["maximum-items"]
|
max_items = config["maximum-items"]
|
||||||
|
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
raise Exception("Path should be a directory:" + str(path))
|
raise Exception("Path should be a directory:" + str(path))
|
||||||
|
|
||||||
children = self.gather_rotation_candidates(path)
|
children = self.gather_rotation_candidates(config, path)
|
||||||
|
|
||||||
# Do we need to rotate anything out?
|
# Do we need to rotate anything out?
|
||||||
if len(children) <= max_items:
|
if len(children) <= max_items:
|
||||||
@ -104,31 +151,35 @@ class BackupRotator:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for purge_index in range(purge_count):
|
for purge_index in range(purge_count):
|
||||||
item_to_purge = self.pick_item_to_purge(children)
|
|
||||||
|
#
|
||||||
|
item_to_purge = self.pick_item_to_purge(config, children)
|
||||||
children.remove(item_to_purge)
|
children.remove(item_to_purge)
|
||||||
self.log("Purging item:", item_to_purge)
|
|
||||||
|
#
|
||||||
if os.path.isfile(item_to_purge):
|
if os.path.isfile(item_to_purge):
|
||||||
os.remove(item_to_purge)
|
self.remove_file(config, item_to_purge)
|
||||||
elif os.path.isdir(item_to_purge):
|
elif os.path.isdir(item_to_purge):
|
||||||
shutil.rmtree(item_to_purge)
|
self.remove_directory(config, item_to_purge)
|
||||||
else:
|
else:
|
||||||
raise Exception("Don't know how to remove this item: " + str(item_to_purge))
|
raise Exception("Don't know how to remove this item: " + str(item_to_purge))
|
||||||
|
|
||||||
def gather_rotation_candidates(self, path):
|
@staticmethod
|
||||||
|
def gather_rotation_candidates(config, path):
|
||||||
|
|
||||||
candidates = []
|
candidates = []
|
||||||
|
|
||||||
if "target-type" not in self.__config.keys():
|
if "target-type" not in config.keys():
|
||||||
raise Exception("Please provide the configuration key: target-type")
|
raise Exception("Please provide the configuration key: target-type")
|
||||||
|
|
||||||
for item_name in os.listdir(path):
|
for item_name in os.listdir(path):
|
||||||
|
|
||||||
item_path = os.path.join(path, item_name)
|
item_path = os.path.join(path, item_name)
|
||||||
|
|
||||||
if self.__config["target-type"] == "file":
|
if config["target-type"] == "file":
|
||||||
if not os.path.isfile(item_path):
|
if not os.path.isfile(item_path):
|
||||||
continue
|
continue
|
||||||
elif self.__config["target-type"] == "directory":
|
elif config["target-type"] == "directory":
|
||||||
if not os.path.isdir(item_path):
|
if not os.path.isdir(item_path):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@ -138,12 +189,13 @@ class BackupRotator:
|
|||||||
|
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
def pick_item_to_purge(self, items):
|
@staticmethod
|
||||||
|
def pick_item_to_purge(config, items):
|
||||||
|
|
||||||
if "date-detection" not in self.__config.keys():
|
if "date-detection" not in config.keys():
|
||||||
raise Exception("Please provide config key: \"date-detection\"")
|
raise Exception("Please provide config key: \"date-detection\"")
|
||||||
|
|
||||||
detection = self.__config["date-detection"]
|
detection = config["date-detection"]
|
||||||
best_item = None
|
best_item = None
|
||||||
best_ctime = None
|
best_ctime = None
|
||||||
for item in items:
|
for item in items:
|
||||||
@ -157,6 +209,32 @@ class BackupRotator:
|
|||||||
raise Exception("Invalid value for \"date-detection\": " + str(detection))
|
raise Exception("Invalid value for \"date-detection\": " + str(detection))
|
||||||
|
|
||||||
return best_item
|
return best_item
|
||||||
|
|
||||||
|
def remove_file(self, config, file_path):
|
||||||
|
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
raise Exception("Tried to remove a file, but this path isn't a file: " + str(file_path))
|
||||||
|
|
||||||
|
if self.__dry_run:
|
||||||
|
self.log("Won't purge file during global-level dry run: ", file_path)
|
||||||
|
elif "dry-run" in config.keys() and config["dry-run"] is True:
|
||||||
|
self.log("Won't purge file during config-level dry run: ", file_path)
|
||||||
|
else:
|
||||||
|
self.log("Purging file:", file_path)
|
||||||
|
os.remove(file_path)
|
||||||
|
|
||||||
|
def remove_directory(self, config, dir_path):
|
||||||
|
|
||||||
|
if not os.path.isdir(dir_path):
|
||||||
|
raise Exception("Tried to remove a directory, but this path isn't a directory: " + str(dir_path))
|
||||||
|
|
||||||
|
if self.__dry_run:
|
||||||
|
self.log("Won't purge directory during global-level dry run: ", dir_path)
|
||||||
|
elif "dry-run" in config.keys() and config["dry-run"] is True:
|
||||||
|
self.log("Won't purge directory during config-level dry run: ", dir_path)
|
||||||
|
else:
|
||||||
|
self.log("Purging directory:", dir_path)
|
||||||
|
shutil.rmtree(dir_path)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
Loading…
Reference in New Issue
Block a user