Ah, I forgot to handle the case where /srv/local-apt-repository doesn't exist 
when the package is installed.  This updated patch (and my latest push on 
salsa.d.o) should fix that.
>From bd063c0a9ba11ff53ba9b233ed5c63a64ee97495 Mon Sep 17 00:00:00 2001
From: Darsey Litzenberger <[email protected]>
Date: Mon, 21 Jul 2025 16:15:08 -0600
Subject: [PATCH 6/7] Fix several error cases; improve comments

Most of the bugs fixed here are related to bash's inconsistent errexit
behavior.  In bash, "set -e" (errexit) has no effect when a conditional
is being evaluated on a compound statement.  For example:

    # The following code prints "after false" and succeeds.
    set -e
    ( false
      echo after false
    ) || false

So, errors went uncaught if apt-ftparchive failed while generating
$REPO/Packages but succeeded while generating $REPO/Sources, or if dpkg
failed to print the architecture list for some reason.

The script might also have broken if apt-ftparchive generated partial
output and the 10-retry limit was exceeded.
---
 rebuild | 70 ++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 47 insertions(+), 23 deletions(-)

diff --git a/rebuild b/rebuild
index 694491b..8178a9c 100755
--- a/rebuild
+++ b/rebuild
@@ -1,52 +1,76 @@
 #!/bin/bash
 
-set -e
+set -eu
 
 DEBS=/srv/local-apt-repository
 REPO=/var/lib/local-apt-repository
 CACHE=/var/cache/local-apt-repository
+ARCHS="$(dpkg --print-architecture && dpkg --print-foreign-architectures)"
 
-if ! test -d $DEBS
-then
-  # We still need ot create the files lest apt will complain
-  > $REPO/Packages
-  > $REPO/Sources
-  rm -f "$REPO"/Contents-*
+generate_index_files() {
+  # We need "|| return" after every command in this function, because "set -e"
+  # has no effect inside a conditional context.
+  # See https://mywiki.wooledge.org/BashPitfalls#errexit
+
+  # This function assumes that we are already inside the REPO directory.
+
+  apt-ftparchive packages --db "$CACHE/cache.db" ../../../"$DEBS" > Packages || return
+  apt-ftparchive sources --db "$CACHE/cache.db" ../../../"$DEBS" > Sources || return
+
+  rm -f Contents-* || return
+
+  for arch in $ARCHS
+  do
+    apt-ftparchive contents --db "$CACHE/cache.db" \
+      --arch "$arch" ../../../"$DEBS" > "Contents-$arch" || return
+  done
+}
+
+# We want apt-ftparchive to generate files with relative paths, and we want
+# this command to fail if the REPO directory does not exist, so change
+# directories before doing anything else.
+cd "$REPO"
 
-else
+has_directory=
+generated=
+if test -d "$DEBS"
+then
+  has_directory=1
 
   # We want to cater for the possibility that something is added to $DEBS as we
   # run, or that a file is slowly written. In this case, we want to wait a bit
   # and restart. But lets bound this to 10 runs.
   for n in $(seq 0 10)
   do
-      # This is the second round alreay, lets wait a while
+      # This is the second round already; let's wait a while.
       if [ "$n" != "0" ]
       then
         echo "Further changes are coming in, waiting..."
         sleep 10
       fi
 
-      # Relative paths work better than absolute
-      (cd $REPO
-      apt-ftparchive packages --db "$CACHE/cache.db" ../../../"$DEBS" > "$REPO/Packages"
-      apt-ftparchive sources --db "$CACHE/cache.db" ../../../"$DEBS" > "$REPO/Sources"
-      rm -f "$REPO"/Contents-*
-      for arch in $(dpkg --print-architecture) $(dpkg --print-foreign-architectures)
-      do
-        apt-ftparchive contents --db "$CACHE/cache.db" --arch "$arch" \
-          ../../../"$DEBS" > "$REPO/Contents-$arch"
-      done
-      ) && break || true
-      # ^ this can fail during a partial write to the directory (which
-      #   would be detected by the loop), so ignore errors here
+      # apt-ftparchive can fail during a partial write to the directory, so
+      # repeat the loop on any errors.
+      generate_index_files || continue
 
+      generated=1
+      break
   done
+fi
 
+if ! [ "$generated" ]
+then
+  # We still need to create the files lest apt will complain
+  > Packages
+  > Sources
+  rm -f Contents-*
 fi
 
 apt-ftparchive \
 	-o "APT::FTPArchive::Release::Origin=local-apt-repository" \
 	-o "APT::FTPArchive::Release::Description=Local repository created by local-apt-repository" \
-	release $REPO > $REPO/Release
+	release . > Release
 
+if [ "$has_directory" ] && ! [ "$generated" ]; then
+  exit 1
+fi
-- 
2.50.0

Reply via email to