-
Notifications
You must be signed in to change notification settings - Fork 0
/
list_backups.py
73 lines (59 loc) · 2.4 KB
/
list_backups.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import argparse
import datetime
import subprocess
from dataclasses import dataclass
from backoff import retry
parser = argparse.ArgumentParser()
parser.add_argument('n_recent', type=int, nargs="?", default=10, help='Analyse the `n` most recent backups')
args = parser.parse_args()
MAX_RETRIES = 5
@dataclass
class Backup:
path: str
def __post_init__(self):
date = self.path.split("/")[-1].split(".")[0]
self.date = datetime.datetime.strptime(date, "%Y-%m-%d-%H%M%S")
time_ago = datetime.datetime.now() - self.date
self.time_ago = f"{time_ago.days}d {time_ago.seconds // 3600}h {time_ago.seconds // 60 % 60}m ago"
@retry(exception=Exception, n_tries=MAX_RETRIES)
def calculate_size(self):
timeout = 45
print(f"\t{self.date} (timeout={timeout}s)...", end=" ")
uniquesize = subprocess.run(["tmutil", "uniquesize", self.path], capture_output=True, text=True, timeout=timeout)
print("Success.")
self.size, _ = uniquesize.stdout.split(" ")
def try_calculate_size(self):
try:
self.calculate_size()
except Exception as e:
self.size = f"ERROR ({MAX_RETRIES} retries)"
@retry(exception=Exception, n_tries=MAX_RETRIES)
def list_backups():
command = ["tmutil", "listbackups", "-m"]
timeout = 45
print(f"Running `{' '.join(command)}` (timeout={timeout}s)...", end=" ")
result = subprocess.run(command, capture_output=True, text=True, timeout=timeout)
if result.returncode != 0:
raise Exception(f"`tmutil listbackups` failed with '{result.stderr}'")
else:
result = result.stdout.splitlines()
print("Found", len(result), "backups.")
return result
status = subprocess.check_output(["tmutil", "status"], text=True, timeout=1).strip()
if "Running = 1;" in status:
print("Time Machine is currently running with status:")
print(status)
print("Please wait for it to finish before running this script.")
exit(1)
backups = list_backups()
backups = [Backup(b) for b in backups[-args.n_recent:]]
print("Calculating size of", len(backups), "most recent backups...")
for backup in backups:
backup.try_calculate_size()
print("========================================")
print("Results:")
for backup in backups:
# Align size as column
backup.time_ago = f"({backup.time_ago})".ljust(20)
print(f"{backup.date} {backup.time_ago} {backup.size:>10}")
exit(0)