Add lockfile attribute
This commit is contained in:
parent
f2bf042549
commit
b21dbd8890
@ -11,7 +11,8 @@ from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
# ========== Constants ==========
|
||||
VALID_DB_COMPRESS_MODES = ["bzip2", "gz", "lzma", "xz"]
|
||||
LOCKFILE_MODE = 0o0000
|
||||
VALID_DB_COMPRESS_MODES = [None, "bzip2", "gz", "lzma", "xz"]
|
||||
|
||||
# ========== Logging Setup ==========
|
||||
syslog = logging.getLogger(__name__)
|
||||
@ -19,20 +20,62 @@ syslog = logging.getLogger(__name__)
|
||||
|
||||
# ========== Classes ==========
|
||||
class PackageManager:
|
||||
def __init__(self, cachedir, db_path, pkglist_cmd):
|
||||
"""Class for abstracting package manager-based operations.
|
||||
|
||||
The package manager can be used in conjunction with a ``Snapshot`` for backups.
|
||||
|
||||
Lockfile Management
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This class can be used as a context manager for creating a lockfile for the
|
||||
specific package manager. This is to prevent transactions from occurring during
|
||||
backup operations which would most likely leave the package manager's database in
|
||||
an inconsistent state on the backup.
|
||||
|
||||
.. note:: Subclasses can override the context manager and implement i.e. blocking until
|
||||
the process is complete with a timeout.
|
||||
"""
|
||||
|
||||
def __init__(self, cachedir=None, db_path=None, lockfile=None, pkglist_cmd=None):
|
||||
"""Default constructor for the PackageManager class.
|
||||
|
||||
:param cachedir: path to the package manager cache directory
|
||||
:type cachedir: str or path-like object
|
||||
:param db_path: path to the package manager database
|
||||
:type db_path: str or path-like object
|
||||
:param lockfile: path to this package manager's lockfile
|
||||
:type lockfile: str
|
||||
:param pkglist_cmd: command to list installed packages to stdout
|
||||
:type pkglist_cmd: str or iterable of str
|
||||
"""
|
||||
self._cachedir = Path(cachedir)
|
||||
self._db_path = Path(db_path)
|
||||
self._lockfile = Path(lockfile)
|
||||
self._pkglist_cmd = pkglist_cmd
|
||||
|
||||
def __enter__(self):
|
||||
"""Create the package manager's lockfile. This prevents transactions
|
||||
from occurring during the backup which could leave the database backup
|
||||
in an inconsistent state.
|
||||
|
||||
The existence of this lockfile is an error, and its meaning is up to
|
||||
the package manager. For example, pacman's db.lck indicates
|
||||
either there is an ongoing transaction in progress or a previous transaction
|
||||
failed and the database is in an inconsistent state.
|
||||
|
||||
:returns: self
|
||||
:rtype: ``PackageManager`` object
|
||||
:raises FileExistsError: if lockfile exists when this method is called
|
||||
"""
|
||||
self._lockfile.touch(mode=0o000)
|
||||
yield self
|
||||
|
||||
def __exit__(self):
|
||||
"""Remove the package manager's lockfile. After this lockfile is closed,
|
||||
the package manager this class abstracts can perform transactions once again.
|
||||
"""
|
||||
self._lockfile.unlink()
|
||||
|
||||
def gen_pkglist(self):
|
||||
"""Generate a text file listing installed packages
|
||||
on the system and return the path to that file.
|
||||
@ -109,6 +152,14 @@ class PackageManager:
|
||||
"""
|
||||
return self._db_path
|
||||
|
||||
@property
|
||||
def lockfile(self):
|
||||
"""
|
||||
:returns: the lockfile path of this package manager
|
||||
:rtype: path-like object
|
||||
"""
|
||||
return self._lockfile
|
||||
|
||||
@property
|
||||
def pkglist_cmd(self):
|
||||
"""
|
||||
|
@ -60,8 +60,11 @@ class TestPackageManagerMethods(unittest.TestCase):
|
||||
|
||||
self.cachedir = "/var/cache/pacman/"
|
||||
self.db_path = "/var/lib/pacman"
|
||||
self.lockfile = "/var/lib/pacman/db.lck"
|
||||
self.pkglist_cmd = ["pacman", "-Qqe"]
|
||||
self.p = PackageManager(self.cachedir, self.db_path, self.pkglist_cmd)
|
||||
self.p = PackageManager(
|
||||
self.cachedir, self.db_path, self.lockfile, self.pkglist_cmd
|
||||
)
|
||||
|
||||
def test_pkglist(self):
|
||||
self.mocked_run.return_value.stdout = "packages"
|
||||
|
Loading…
x
Reference in New Issue
Block a user