> 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; } } }
test.sh
Description: Bourne shell script