> use the "hashref" based autoscript?

The attached updated diff switches
from strings and sed expressions
back to arrays (again) and hashrefs (new).

> The "justdirs" is supposed to be in "opposite" order of "dirs"
> ("justdirs" are in "removal order" while "dirs" are in "creation order")
> but as far as I can see that ordering is not preserved in the patch.

They are not supposed to be in opposite order.
Actually, @justdirs contains strictly less elements than @dirs.
During the same recursive traversal,

* @dirs is appended each parent before its childs. This is the order
  in which subdirectories are discovered in $tmpdir/usr/local/ during
  the traversal, so it is by construction compatible with later
  re-creation during install.

* @justdirs is appended all childs before their parent.  The list is
  constructed in the same code part actually removing the directory
  from $tmpdir/usr/local/, so this order is compatible with
  uninstallation

* In both lists, the childs are traversed in alphabetical order to
  ensure reproducible scripts. This is unrelated with the two previous
  constraints.

If this explanation seems convincing, please paste it inside comments
before the File::Find::file recursion.

> I think dh_usrlocal might be ready for some test cases to avoid future
> breakage.

The attached test.sh implements some suggested tests.
--- a/dh_usrlocal
+++ b/dh_usrlocal
@@ -77,54 +77,49 @@
 
 	if (-d "$tmp/usr/local") {
 		my (@dirs, @justdirs);
-		find({bydepth => 1,
-		      no_chdir => 1,
+		find({no_chdir => 1,
+		      preprocess => sub {
+			# Ensure a reproducible traversal.
+			return sort @_;
+		      },
+		      postprocess => sub {
+			# Uninstall, unless a direct child of /usr/local.
+			$_ = $File::Find::dir;
+			s!^\Q$tmp\E!!;
+			push @justdirs, $_ if m!/usr/local/.*/!;
+			# Remove a directory after its childs.
+			doit('rmdir', $File::Find::dir);
+		      },
 		      wanted => sub {
+			# rmdir would fail later anyways.
+			error("${File::Find::name} is not a directory")
+				if not -d $File::Find::name;
+			# Install directory before its childs.
 			my $fn = $File::Find::name;
-			if (-d $fn) {
-				my $user = 'root';
-				my $group = 'staff';
-				my $mode = '02775';
-				if (should_use_root()) {
-					my $stat = stat $fn;
-					$user = getpwuid $stat->uid;
-					$group = getgrgid $stat->gid;
-					$mode = sprintf "%04lo", ($stat->mode & 07777);
-					if ($stat->uid == 0 && $stat->gid == 0) {
-						$group = 'staff';
-						$mode = '02775';
-					}
+			$fn =~ s!^\Q$tmp\E!!;
+			return if $fn eq '/usr/local';
+			if (should_use_root()) {
+				my $stat = stat $File::Find::dir;
+				if ($stat->uid == 0 && $stat->gid == 0) {
+					push @dirs, "$fn 02775 root staff";
+				} else {
+					my $user = getpwuid $stat->uid;
+					my $group = getgrgid $stat->gid;
+					my $mode = sprintf "%04lo", ($stat->mode & 07777);
+					push @dirs, "$fn $mode $user $group";
 				}
-
-
-
-				$fn =~ s!^\Q$tmp\E!!;
-				return if $fn eq '/usr/local';
-				
-				# @dirs is in parents-first order for dir creation...
-				unshift @dirs, "$fn $mode $user $group";
-				# ...whereas @justdirs is depth-first for removal.
-				push @justdirs, $fn;
-				doit('rmdir', $_);
-			}
-			else {
-				warning("$fn is not a directory");
+			} else {
+				push @dirs, "$fn 02775 root staff";
 			}
 		      }}, "$tmp/usr/local");
-		doit('rmdir', "$tmp/usr/local");
-	
-		my $bs = "\\";     # A single plain backslash
-		my $ebs = $bs x 2; # Escape the backslash from the shell
+
 		# This constructs the body of a 'sed' c\ expression which
 		# is parsed by the shell in double-quotes
-		my $dirs = join("$ebs\n", sort @dirs);
-		pop @justdirs; # don't remove directories directly in /usr/local
-		my $justdirs = join("$ebs\n", reverse sort @justdirs);
 		if (! $dh{NOSCRIPTS}) { 
 			autoscript($package,"postinst", "postinst-usrlocal",
-				   "/#DIRS#/ c${ebs}\n${dirs}");
+				   { 'DIRS' => join ("\n", @dirs)}) if @dirs;
 			autoscript($package,"prerm", "prerm-usrlocal",
-				   "/#JUSTDIRS#/ c${ebs}\n${justdirs}") if length $justdirs;
+				   { 'JUSTDIRS' => join ("\n", @justdirs)}) if @justdirs;
 		}
 	}
 }

Attachment: test.sh
Description: Bourne shell script

Reply via email to