Add metadata handling capabilities and adjust attributes accordingly

This commit is contained in:
Eric Torres 2019-03-29 15:25:52 -07:00
parent 0254a2fa2e
commit fde99f6604

View File

@ -15,6 +15,13 @@ from rbackup.hierarchy.snapshot import Snapshot
syslog = logging.getLogger(__name__) syslog = logging.getLogger(__name__)
# ========== Constants ==========
METADATA_READ = "rb"
METADATA_WRITE = "wb"
DIRMODE = 0o755
FILEMODE = 0o644
# ========== Classes ========== # ========== Classes ==========
class Repository(Hierarchy): class Repository(Hierarchy):
"""A class for interacting with a backup repository. """A class for interacting with a backup repository.
@ -39,6 +46,7 @@ class Repository(Hierarchy):
---------- ----------
* path (inherited from Hierarchy) * path (inherited from Hierarchy)
* name (inherited from Hierarchy) * name (inherited from Hierarchy)
* metadata_path (inherited from Hierarchy)
* current_snapshot - either the most recent snapshot * current_snapshot - either the most recent snapshot
before running create_snapshot() or the new snapshot before running create_snapshot() or the new snapshot
created after running create_snapshot() created after running create_snapshot()
@ -70,24 +78,34 @@ class Repository(Hierarchy):
self._snapshot_index = 0 self._snapshot_index = 0
if self._metadata_path.exists(): if not self.metadata_path.exists():
with self._metadata_path.open(mode="rb") as metadata_file: self._init_new_repository()
self._snapshots = pickle.load(metadata_file)
else: else:
self._snapshots = [] self._read_metadata()
try: def _init_new_repository(self):
self._current_snapshot = self.snapshots[-1] self.metadata_path.parent.mkdir(mode=DIRMODE, exist_ok=True)
except IndexError: self.metadata_path.touch(mode=FILEMODE)
self._current_snapshot = None
self._data = {"snapshots": [], "current_snapshot": None}
self._write_metadata()
def _read_metadata(self):
with self.metadata_path.open(mode=METADATA_READ) as mfile:
self._data = pickle.load(mfile)
def _write_metadata(self):
with self.metadata_path.open(mode=METADATA_WRITE) as mfile:
pickle.dump(self._data, mfile)
def __len__(self): def __len__(self):
"""Return the number of snapshots in this Repository.""" """Return the number of snapshots in this Repository."""
return len(self.snapshots) return len(self._data["snapshots"])
def __getitem__(self, position): def __getitem__(self, position):
"""Retrieve a Snapshot at a certain index.""" """Retrieve a Snapshot at a certain index."""
return self.snapshots[position] return self.data["snapshots"][position]
def __delitem__(self, s): def __delitem__(self, s):
"""Delete a Snapshot in this Repository.""" """Delete a Snapshot in this Repository."""
@ -103,7 +121,7 @@ class Repository(Hierarchy):
def __next__(self): def __next__(self):
"""Return the next Snapshot in this Repository.""" """Return the next Snapshot in this Repository."""
try: try:
result = self.snapshots[self._snapshot_index] result = self._data["snapshots"][self._snapshot_index]
self._snapshot_index += 1 self._snapshot_index += 1
return result return result
except IndexError: except IndexError:
@ -142,7 +160,7 @@ class Repository(Hierarchy):
date date
:rtype: list of Snapshot objects :rtype: list of Snapshot objects
""" """
return self._snapshots return self._data["snapshots"]
@property @property
def empty(self): def empty(self):
@ -160,7 +178,7 @@ class Repository(Hierarchy):
:rtype: bool :rtype: bool
""" """
return self.snapshots == [] return self._data["snapshots"] == []
@property @property
def current_snapshot(self): def current_snapshot(self):
@ -168,37 +186,36 @@ class Repository(Hierarchy):
:rtype: Snapshot object :rtype: Snapshot object
""" """
return self._current_snapshot return self._data["current_snapshot"]
def create_snapshot( def create_snapshot(self, name=None):
self, name=datetime.datetime.utcnow().isoformat().replace(":", "-")
):
"""Create a new snapshot in this repository. """Create a new snapshot in this repository.
This method is non-intrusive in that it will not This method is non-intrusive in that it will not
make any changes in the filesystem when called. make any changes in the filesystem when called.
:param name: the name of the snapshot
:type name: str
:return: a new Snapshot object :return: a new Snapshot object
""" """
syslog.debug("Creating snapshot") syslog.debug("Creating snapshot")
if not isinstance(name, str):
raise ValueError(f"{name} is not a valid type for a snapshot name")
snapshot_name = ( snapshot_name = (
name name
if name is not None if name is not None
else datetime.datetime.utcnow().isoformat().replace(":", "-") else datetime.datetime.utcnow().isoformat().replace(":", "_")
) )
path = self.snapshot_dir / f"snapshot-{snapshot_name}" path = self.snapshot_dir / snapshot_name
self._current_snapshot = Snapshot(path) self._data["current_snapshot"] = Snapshot(path)
self.snapshots.append(self._current_snapshot) self._data["snapshots"].append(self._data["current_snapshot"])
self._write_metadata()
syslog.debug("Snapshot created") syslog.debug("Snapshot created")
syslog.debug(f"Snapshot name: {self.current_snapshot.name}") syslog.debug(f"Snapshot name: {self.current_snapshot.name}")
return self._current_snapshot return self._data["current_snapshot"]
# ========== Functions ========== # ========== Functions ==========