Move metadata handling to the Hierarchy class
This commit is contained in:
parent
874f94c5fc
commit
5cca10a12b
@ -4,6 +4,7 @@
|
|||||||
:synopsis: Classes for creating the backup hierarchy.
|
:synopsis: Classes for creating the backup hierarchy.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import pickle
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -11,6 +12,11 @@ from pathlib import Path
|
|||||||
syslog = logging.getLogger(__name__)
|
syslog = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# ========== Constants ==========
|
||||||
|
METADATA_READ = "rb"
|
||||||
|
METADATA_WRITE = "wb"
|
||||||
|
|
||||||
|
|
||||||
# ========== Classes ==========
|
# ========== Classes ==========
|
||||||
class Hierarchy:
|
class Hierarchy:
|
||||||
"""A class for organizing the backup root hierarchy.
|
"""A class for organizing the backup root hierarchy.
|
||||||
@ -24,6 +30,12 @@ class Hierarchy:
|
|||||||
* path
|
* path
|
||||||
* name
|
* name
|
||||||
* metadata_path
|
* metadata_path
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
* read_metadata - read this Hierarchy's metadata from a file
|
||||||
|
and return it
|
||||||
|
* write_metadata - write this Hierarchy's metadata to a file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, dest):
|
def __init__(self, dest):
|
||||||
@ -77,6 +89,20 @@ class Hierarchy:
|
|||||||
"""
|
"""
|
||||||
return self.path / ".metadata"
|
return self.path / ".metadata"
|
||||||
|
|
||||||
|
def read_metadata(self):
|
||||||
|
"""Read this repository's metadata from its file and
|
||||||
|
then return it.
|
||||||
|
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
with self.metadata_path.open(mode=METADATA_READ) as mfile:
|
||||||
|
return pickle.load(mfile)
|
||||||
|
|
||||||
|
def write_metadata(self):
|
||||||
|
"""Write this repository's metadata to its file."""
|
||||||
|
with self.metadata_path.open(mode=METADATA_WRITE) as mfile:
|
||||||
|
pickle.dump(self._data, mfile)
|
||||||
|
|
||||||
|
|
||||||
# ========== Functions ==========
|
# ========== Functions ==========
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import datetime
|
import datetime
|
||||||
import pickle
|
|
||||||
|
|
||||||
from rbackup.hierarchy.hierarchy import Hierarchy
|
from rbackup.hierarchy.hierarchy import Hierarchy
|
||||||
from rbackup.hierarchy.snapshot import Snapshot
|
from rbackup.hierarchy.snapshot import Snapshot
|
||||||
@ -16,8 +15,6 @@ syslog = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
# ========== Constants ==========
|
# ========== Constants ==========
|
||||||
METADATA_READ = "rb"
|
|
||||||
METADATA_WRITE = "wb"
|
|
||||||
DIRMODE = 0o755
|
DIRMODE = 0o755
|
||||||
FILEMODE = 0o644
|
FILEMODE = 0o644
|
||||||
|
|
||||||
@ -55,7 +52,10 @@ class Repository(Hierarchy):
|
|||||||
|
|
||||||
Methods
|
Methods
|
||||||
-------
|
-------
|
||||||
* create_snapshot() - create a new snapshot, then update current_snapshot
|
* create_snapshot - create a new snapshot, then update current_snapshot
|
||||||
|
* gen_snapshot_path - generate a path for a snapshot given by name
|
||||||
|
* read_metadata (inherited from Hierarchy)
|
||||||
|
* write_metadata (inherited from Hierarchy)
|
||||||
|
|
||||||
Directory Structure
|
Directory Structure
|
||||||
-------------------
|
-------------------
|
||||||
@ -79,25 +79,16 @@ class Repository(Hierarchy):
|
|||||||
self._snapshot_index = 0
|
self._snapshot_index = 0
|
||||||
|
|
||||||
if not self.metadata_path.exists():
|
if not self.metadata_path.exists():
|
||||||
|
self._data = {"snapshots": [], "current_snapshot": None}
|
||||||
self._init_new_repository()
|
self._init_new_repository()
|
||||||
else:
|
else:
|
||||||
self._read_metadata()
|
self._data = self.read_metadata()
|
||||||
|
|
||||||
def _init_new_repository(self):
|
def _init_new_repository(self):
|
||||||
self.metadata_path.parent.mkdir(mode=DIRMODE, exist_ok=True)
|
self.metadata_path.parent.mkdir(mode=DIRMODE, exist_ok=True)
|
||||||
self.metadata_path.touch(mode=FILEMODE)
|
self.metadata_path.touch(mode=FILEMODE)
|
||||||
|
|
||||||
self._data = {"snapshots": [], "current_snapshot": None}
|
self.write_metadata()
|
||||||
|
|
||||||
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."""
|
||||||
@ -210,7 +201,12 @@ class Repository(Hierarchy):
|
|||||||
self._data["current_snapshot"] = Snapshot(path)
|
self._data["current_snapshot"] = Snapshot(path)
|
||||||
self._data["snapshots"].append(self._data["current_snapshot"])
|
self._data["snapshots"].append(self._data["current_snapshot"])
|
||||||
|
|
||||||
self._write_metadata()
|
self.write_metadata()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._data["current_snapshot"].path.mkdir(mode=DIRMODE, parents=True)
|
||||||
|
except FileExistsError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
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}")
|
||||||
|
@ -24,6 +24,11 @@ class Snapshot(Hierarchy):
|
|||||||
* etc_dir
|
* etc_dir
|
||||||
* home_dir
|
* home_dir
|
||||||
* root_home_dir
|
* root_home_dir
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
* read_metadata (inherited from Hierarchy)
|
||||||
|
* write_metadata (inherited from Hierarchy)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
|
@ -29,18 +29,21 @@ class TestRepositoryPreCreate(unittest.TestCase):
|
|||||||
self.patched_path = patch.object(
|
self.patched_path = patch.object(
|
||||||
Repository, "metadata_path", new_callable=PropertyMock
|
Repository, "metadata_path", new_callable=PropertyMock
|
||||||
)
|
)
|
||||||
|
self.patched_r_metadata = patch.object(Repository, "read_metadata")
|
||||||
|
self.patched_w_metadata = patch.object(Repository, "write_metadata")
|
||||||
self.patched_snapshot = patch(
|
self.patched_snapshot = patch(
|
||||||
f"{TESTING_PACKAGE}.repository.Snapshot", spec_set=Snapshot
|
f"{TESTING_PACKAGE}.repository.Snapshot", spec_set=Snapshot
|
||||||
)
|
)
|
||||||
self.patched_pickle = patch(f"{TESTING_PACKAGE}.repository.pickle")
|
|
||||||
|
|
||||||
|
self.mocked_r_metadata = self.patched_r_metadata.start()
|
||||||
|
self.mocked_w_metadata = self.patched_w_metadata.start()
|
||||||
self.mocked_path = self.patched_path.start()
|
self.mocked_path = self.patched_path.start()
|
||||||
self.mocked_snapshot = self.patched_snapshot.start()
|
self.mocked_snapshot = self.patched_snapshot.start()
|
||||||
self.mocked_pickle = self.patched_pickle.start()
|
self.mocked_pickle = self.patched_pickle.start()
|
||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_empty(self, l):
|
def test_empty(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
@ -53,7 +56,7 @@ class TestRepositoryPreCreate(unittest.TestCase):
|
|||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_len(self, l):
|
def test_len(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
@ -64,15 +67,15 @@ class TestRepositoryPreCreate(unittest.TestCase):
|
|||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_current_snapshot(self, l):
|
def test_current_snapshot(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if l == []:
|
if l == []:
|
||||||
self.mocked_pickle.load.return_value["current_snapshot"] = None
|
self.mocked_r_metadata.return_value["current_snapshot"] = None
|
||||||
else:
|
else:
|
||||||
self.mocked_pickle.load.return_value["current_snapshot"] = l[-1]
|
self.mocked_r_metadata.return_value["current_snapshot"] = l[-1]
|
||||||
repo = Repository("backup")
|
repo = Repository("backup")
|
||||||
|
|
||||||
if l == []:
|
if l == []:
|
||||||
@ -83,8 +86,9 @@ class TestRepositoryPreCreate(unittest.TestCase):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.patched_path.stop()
|
self.patched_path.stop()
|
||||||
|
self.patched_r_metadata.stop()
|
||||||
|
self.patched_w_metadata.stop()
|
||||||
self.patched_snapshot.stop()
|
self.patched_snapshot.stop()
|
||||||
self.patched_pickle.stop()
|
|
||||||
|
|
||||||
|
|
||||||
class TestRepositoryPostCreate(unittest.TestCase):
|
class TestRepositoryPostCreate(unittest.TestCase):
|
||||||
@ -94,26 +98,28 @@ class TestRepositoryPostCreate(unittest.TestCase):
|
|||||||
self.patched_path = patch.object(
|
self.patched_path = patch.object(
|
||||||
Repository, "metadata_path", new_callable=PropertyMock
|
Repository, "metadata_path", new_callable=PropertyMock
|
||||||
)
|
)
|
||||||
|
self.patched_r_metadata = patch.object(Repository, "read_metadata")
|
||||||
|
self.patched_w_metadata = patch.object(Repository, "write_metadata")
|
||||||
self.patched_snapshot = patch(
|
self.patched_snapshot = patch(
|
||||||
f"{TESTING_PACKAGE}.repository.Snapshot", spec_set=Snapshot
|
f"{TESTING_PACKAGE}.repository.Snapshot", spec_set=Snapshot
|
||||||
)
|
)
|
||||||
self.patched_pickle = patch(f"{TESTING_PACKAGE}.repository.pickle")
|
|
||||||
|
|
||||||
self.mocked_path = self.patched_path.start()
|
self.mocked_path = self.patched_path.start()
|
||||||
|
self.mocked_r_metadata = self.patched_r_metadata.start()
|
||||||
|
self.mocked_w_metadata = self.patched_w_metadata.start()
|
||||||
self.mocked_snapshot = self.patched_snapshot.start()
|
self.mocked_snapshot = self.patched_snapshot.start()
|
||||||
self.mocked_pickle = self.patched_pickle.start()
|
|
||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_empty(self, l):
|
def test_empty(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if l == []:
|
if l == []:
|
||||||
self.mocked_pickle.load.return_value["current_snapshot"] = None
|
self.mocked_r_metadata.return_value["current_snapshot"] = None
|
||||||
else:
|
else:
|
||||||
self.mocked_pickle.load.return_value["current_snapshot"] = l[-1]
|
self.mocked_r_metadata.return_value["current_snapshot"] = l[-1]
|
||||||
repo = Repository("backup")
|
repo = Repository("backup")
|
||||||
|
|
||||||
repo.create_snapshot()
|
repo.create_snapshot()
|
||||||
@ -122,7 +128,7 @@ class TestRepositoryPostCreate(unittest.TestCase):
|
|||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_len(self, l):
|
def test_len(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
@ -135,7 +141,7 @@ class TestRepositoryPostCreate(unittest.TestCase):
|
|||||||
|
|
||||||
@given(lists(builds(Snapshot, text()), unique=True))
|
@given(lists(builds(Snapshot, text()), unique=True))
|
||||||
def test_current_snapshot(self, l):
|
def test_current_snapshot(self, l):
|
||||||
self.mocked_pickle.load.return_value = {
|
self.mocked_r_metadata.return_value = {
|
||||||
"snapshots": l.copy(),
|
"snapshots": l.copy(),
|
||||||
"current_snapshot": l[-1] if l else None,
|
"current_snapshot": l[-1] if l else None,
|
||||||
}
|
}
|
||||||
@ -148,5 +154,6 @@ class TestRepositoryPostCreate(unittest.TestCase):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.patched_path.stop()
|
self.patched_path.stop()
|
||||||
|
self.patched_r_metadata.stop()
|
||||||
|
self.patched_w_metadata.stop()
|
||||||
self.patched_snapshot.stop()
|
self.patched_snapshot.stop()
|
||||||
self.patched_pickle.stop()
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user