Source code for btrsync.btrfs.parse

#!/usr/bin/env python

# Copyright © 2023 Andrei Tatar <andrei.ttr@gmail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later


"""
Parsers for the output of ``btrfs`` subcommands.
"""


def _tabsplit(line): return (x.strip() for x in line.split('\t') if x)
def _valid(v): return None if v == '-' else v


class _BaseParser:
	"""Generic line-oriented parser base class; does not actually parse anything."""
	def __init__(self, lines):
		self.lines = lines

	@classmethod
	def from_stdout(cls, out):
		"""Construct parser from raw command output (UTF-8 encoded bytes)."""
		return cls(out.decode('utf-8').splitlines())


[docs]class List(_BaseParser): """Parse the `lines` of output of ``btrfs subvolume list -t ...`` into an iterable of :class:`dict` instances describing subvolumes.""" def __iter__(self): it = iter(self.lines) hdrs = list(_tabsplit(next(it))) line = next(it) if not line.startswith('-'): raise ValueError(f"Expected separator on line 2, got `{line}'") yield from (dict(zip(hdrs, (_valid(v) for v in _tabsplit(line)))) for line in it)
[docs]class Show(_BaseParser): """Parse the `lines` of output of ``btrfs subvolume show ...`` into an iterable containing the filesystem path and a :class:`dict` of properties.""" def __iter__(self): it = iter(self.lines) path = next(it) yield path stats = {} ml = None for line in it: k, *v = _tabsplit(line) if not v: if ml is None: mlk = k ml = [] else: ml.append(k) else: if ml is not None: stats[mlk] = ml ml = None stats[k] = _valid(' '.join(v)) if ml is not None: stats[mlk] = ml yield stats