Skip to content

Commit

Permalink
Restore compatibility with older macOS versions
Browse files Browse the repository at this point in the history
df's --libxo argument is only available since Sonoma.

Also: df also returns the device; no need to call 'diskutil info'.
  • Loading branch information
brechtm committed Feb 10, 2024
1 parent cf53a75 commit 644211c
Showing 1 changed file with 11 additions and 18 deletions.
29 changes: 11 additions & 18 deletions thriftybackup/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,21 @@ def __init__(self, name, source, destination, interval, threshold,
self.dry_run = dry_run

@cached_property
def source_volume(self):
df = self._run([DF, '--libxo', 'json', self.source], echo=self.echo,
check=True, capture_output=True).stdout
filesystem, = json.loads(df)['storage-system-information']['filesystem']
mounted_on = filesystem['mounted-on']
def source_device_volume(self):
df = self._run([DF, self.source], encoding='utf-8', check=True,
capture_output=True, echo=self.echo).stdout
_, data = df.splitlines()
device, *_, mounted_on = data.split(maxsplit=8)
if mounted_on == '/':
raise RuntimeError("Cannot back up the root volume")
return mounted_on
return device, mounted_on

@property
def exclude_file(self):
return CONFIG_DIR / f'{self.name}.exclude'

def get_last_snapshot(self):
try:
du_info = self._run([DISKUTIL, 'info', '-plist', self.source_volume],
echo=self.echo, check=True, capture_output=True).stdout
except CalledProcessError as exc:
if exc.returncode == 1:
raise VolumeNotMounted(self.source_volume)
raise
device = plistlib.loads(du_info)['DeviceIdentifier']
device, _ = self.source_device_volume
while True:
output = self._run([DISKUTIL, 'apfs', 'listSnapshots', '-plist', device],
echo=self.echo, check=True, capture_output=True).stdout
Expand Down Expand Up @@ -306,8 +299,8 @@ def mount_snapshot(self, device, snapshot):
mount_point = Path(self._tempdir.name)
print(f'Mounting {snapshot} at {mount_point}')
try:
self._run([MOUNT_APFS, '-s', snapshot, '-o', 'nobrowse',
f'/dev/{device}', mount_point], echo=self.echo, check=True)
self._run([MOUNT_APFS, '-s', snapshot, '-o', 'nobrowse', device,
mount_point], echo=self.echo, check=True)
except CalledProcessError as cpe:
if cpe.returncode == 75:
raise TimeMachineBackupInProgress
Expand Down Expand Up @@ -339,8 +332,8 @@ def get_user_feedback(self, tree):
return backup_size, exclude

def sync_popen(self, *args, dry_run=False):
source_root = ('/' if self.source_volume == '/System/Volumes/Data'
else self.source_volume)
_, volume = self.source_device_volume
source_root = '/' if volume == '/System/Volumes/Data' else volume
snapshot_source = self.mount_point / self.source.relative_to(source_root)
extra = list(chain(['--bwlimit', self.bwlimit] if self.bwlimit else [],
['--dry-run'] if dry_run else [],
Expand Down

0 comments on commit 644211c

Please sign in to comment.