]> git.ipfire.org Git - pbs.git/commitdiff
repositories: Compose them seperately and atomically swap
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Mar 2023 11:05:40 +0000 (11:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Mar 2023 11:05:40 +0000 (11:05 +0000)
We will now create the repositories in our temporary space, which will
allow us to be sure that we generated a consistent repository.

We will then swap the new directory with the former one atomically so
that the repository is accessible at all times.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/buildservice/repository.py

index 58d44210baeacd63b2066f1cf9953f78dd39ff16..6ea60abe5e014817ad0bf8dcc0133e946ea40cdd 100644 (file)
@@ -6,6 +6,8 @@ import datetime
 import io
 import logging
 import os.path
+import shutil
+import tempfile
 
 import pakfire
 
@@ -614,17 +616,40 @@ class Repository(base.DataObject):
        def _write(self):
                log.info("Writing repository %s..." % self)
 
+               # Write any new repositories to the temporary space first
+               tmp = self.backend.path("tmp")
+
                # Create a new pakfire instance
-               with self.pakfire() as p:
-                       for arch in self.arches:
+               with tempfile.TemporaryDirectory(dir=tmp, prefix="pakfire-repo-") as t:
+                       with self.pakfire() as p:
+                               for arch in self.arches:
+                                       # Destination path for this architecture
+                                       path = os.path.join(t, arch)
+
+                                       # Fetch packages
+                                       packages = self.get_packages(arch)
+
+                                       # Make filelist (if they exist)
+                                       files = [p.path for p in packages if os.path.exists(p.path)]
+
+                                       # Write repository metadata
+                                       p.repo_compose(path=path, files=files)
+
+                       # Mark the repository as read-only
+                       os.chmod(t, 0o755)
+
+                       # Perform an atomic replace of the repository directory
+                       with tempfile.TemporaryDirectory(dir=tmp, prefix="pakfire-repo-") as bin:
                                # Local path
-                               path = self.local_path(arch)
+                               path = self.local_path()
 
-                               # Fetch packages
-                               packages = self.get_packages(arch)
+                               # Move the old data to the temporary space
+                               try:
+                                       shutil.move(path, bin)
 
-                               # Make filelist (if they exist)
-                               files = [p.path for p in packages if os.path.exists(p.path)]
+                               # Ignore if this repository is being created for the first time
+                               except FileNotFoundError:
+                                       pass
 
-                               # Write repository metadata
-                               p.repo_compose(path=path, files=files)
+                               # Move the new repository data to its destination
+                               shutil.move(t, path)