commit 66d262dd173588e75aab1e228eb3f10817d5cbea Author: Craig Date: Wed Apr 23 10:40:18 2025 +0100 Initial commit to spin out into own repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..49d6a5a --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# simple-backup +This creates a backup on the local filesystem, but does not persist it anywhere else. Right now +the best solution i have to to manually upload this to proton drive. + +## configure +Can add new backups to this by adding another conf file. See services.json for examples and exclude patterns for more details. + +## running +Can run with ./backup.py, or create a cron job. +current crontab entry is. (every sat at 0105.) +``` +sudo crontab -e +5 1 * * 6 /home/craig/services/simple-backup/backup.py >> /var/log/simple-backup.log 2>&1 +``` +want to change this to once a week or something, just like on sunday +## exlude patterns +Uses simple "filter" in "path", so no globbing/regexing. + +For directories, having a trailing slash means it includes the dir but none of its contents. \ No newline at end of file diff --git a/backup.py b/backup.py new file mode 100755 index 0000000..e936edc --- /dev/null +++ b/backup.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 +from pathlib import Path +import json +import tarfile +import datetime +from functools import partial +import time +def tar_filter(filters, tarinfo): + if any([filter_name in tarinfo.name for filter_name in filters]): + print(f"\tFiltering: {tarinfo.name}") + return None + return tarinfo + +def local_backup(output_dir: Path, backup_name: str, inputs: list, ignore_patterns: list): + current_time = datetime.datetime.now().isoformat() + start = time.time() + archive_path = output_dir / f"{backup_name}-{current_time}.tar.gz" + filter_function = partial(tar_filter, ignore_patterns) + print(archive_path) + with tarfile.open(archive_path, "w:xz") as f: + for file_or_dir in inputs: + file_or_dir = Path(file_or_dir).expanduser().resolve() + print(f"Compressing: {file_or_dir}") + f.add(file_or_dir, filter=filter_function) + + print(f"Total time: {(time.time() - start) / 60}mins") + + +def backup_all(): + config_dir = Path(__file__).parent / "configs" + config_files = sorted(config_dir.glob("*")) + print(config_files) + for file in config_files: + text = file.read_text() + config = json.loads(text) + output_dir = Path(config["outputDir"]).expanduser().resolve() + inputs = config["inputs"] + ignore_patterns = config["ignorePatterns"] + backup_name = file.stem + local_backup(output_dir, backup_name, inputs, ignore_patterns) +if __name__ == "__main__": + backup_all() \ No newline at end of file diff --git a/configs/services.json b/configs/services.json new file mode 100644 index 0000000..f09b48f --- /dev/null +++ b/configs/services.json @@ -0,0 +1,10 @@ +{ + "outputDir": "/home/craig/backups/", + "inputs": [ + "/home/craig/services/" + ], + "ignorePatterns": [ + "terraria/", + "netdata/" + ] +} \ No newline at end of file diff --git a/configs/terraria.json b/configs/terraria.json new file mode 100644 index 0000000..9cf27e4 --- /dev/null +++ b/configs/terraria.json @@ -0,0 +1,8 @@ +{ + "outputDir": "/home/craig/backups/", + "inputs": [ + "/home/craig/services/terraria/modded/tModLoader/Worlds/" + ], + "ignorePatterns": [ + ] +} \ No newline at end of file