Thanks for the additional details. Find attached a patch which splits the functionality into the new dh_missing helper.
Aside from the fact that documentation is still missing, what are your thoughts on that patch? Once documentation is added, could we merge it, then change dh_installman and dh_installdocs? Thanks! On Sun, Mar 26, 2017 at 10:13 AM, Niels Thykier <[email protected]> wrote: > Michael Stapelberg: > > On Thu, Mar 23, 2017 at 9:43 PM, Niels Thykier <[email protected]> > wrote: > > > >> Michael Stapelberg: > >>> Sorry for the late reply. > >>> > >> > >> Hi again, :) > >> > >>> [...] > >>> > >>> By “defer it”, what exactly do you mean? Checking for files which were > >> not > >>> installed? > >>> > >> > >> Put the logic into a separate helper, which has - as sole purpose - the > >> responsibility for doing "list/fail-on-missing" checks. > >> > > > > Thanks for clarifying. Would dh_missing be an okay name? > > > > I believe it would. I did think of a couple of alternatives as well: > * dh_missing > * dh_check-missing > * dh_check-not-installed > > (The latter due to the "config" file being called "debian/not-installed"). > > If you write the tool, you get to decide the name :) (within reason :P) > > > > >> > >>> > >>> [...] > >>> > >> > >> To begin with, I think I would just log the original pattern (for source > >> files) and let this new helper "re-expand" it. If performance becomes > >> an issue, we can revisit that decision. The simpler it is to retro-fit > >> this new functionality into an existing helper, the easier we can have > >> "third-party" tools adopt it. :) > >> > > > > Makes sense. > > > > I looked at dh_installdocs and it’s actually way more complicated than I > > imagined. > > > > The current check is only looking at "SOURCEDIR" (with "." converted > into "debian/tmp"). As I recall, dh_installdocs pulls its source files > from "." and "debian" so it is should not be affected (at lot at least). > > > It’s too bad we don’t have a point through which all files must pass > (like > > install_file), otherwise the change would be simple. > > > > Indeed. In fact, invented install_file (et al) is a recent invention to > prepare for things like this. Although it had less coverage than I had > hoped. > > > Would it be okay to convert the helpers one-by-one to use the new > > mechanism? If not, I don’t think I have enough motivation to actually > > update all dh_* programs to log their files. > > > > [...] > > Yes, provided that the conversion is backwards compatible. > > I think dh_install and dh_installman would be the two starting points. > Once we have those, we can enable the new tool in compat 11 and see how > it works (plus do some incremental improvements from there). > > Thanks, > ~Niels > > > > -- Best regards, Michael
From e41b275eb7e2f5ccd49886570edebd5d4c4b4c40 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg <[email protected]> Date: Sun, 26 Mar 2017 14:20:02 +0200 Subject: [PATCH] =?UTF-8?q?Move=20dh=5Finstall=E2=80=99s=20--{list,fail}-m?= =?UTF-8?q?issing=20to=20dh=5Fmissing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit splits dh_install’s --list-missing and --fail-missing functionality into the separate helper dh_missing. To make this work, dh_install logs its source patterns and dh_missing reads these patterns, treating them as installed. This allows us to address #415396, i.e. recognize files installed by other helpers (e.g. dh_installman) as installed. --- Debian/Debhelper/Dh_Lib.pm | 14 ++++++++ dh_install | 47 ++---------------------- dh_missing | 80 +++++++++++++++++++++++++++++++++++++++++ t/dh_missing/Makefile | 6 ++++ t/dh_missing/debian/changelog | 5 +++ t/dh_missing/debian/compat | 1 + t/dh_missing/debian/control | 20 +++++++++++ t/dh_missing/debian/foo.install | 1 + t/dh_missing/dh_missing.t | 50 ++++++++++++++++++++++++++ t/dh_missing/file-for-foo | 1 + 10 files changed, 181 insertions(+), 44 deletions(-) create mode 100755 dh_missing create mode 100644 t/dh_missing/Makefile create mode 100644 t/dh_missing/debian/changelog create mode 100644 t/dh_missing/debian/compat create mode 100644 t/dh_missing/debian/control create mode 100644 t/dh_missing/debian/foo.install create mode 100755 t/dh_missing/dh_missing.t create mode 100644 t/dh_missing/file-for-foo diff --git a/Debian/Debhelper/Dh_Lib.pm b/Debian/Debhelper/Dh_Lib.pm index f4b9ca26..72448058 100644 --- a/Debian/Debhelper/Dh_Lib.pm +++ b/Debian/Debhelper/Dh_Lib.pm @@ -50,6 +50,7 @@ use vars qw(@EXPORT %dh); &generated_file &autotrigger &package_section &restore_file_on_clean &restore_all_files &open_gz &reset_perm_and_owner &deprecated_functionality + &log_installed_files ); # The Makefile changes this if debhelper is installed in a PREFIX. @@ -1455,6 +1456,19 @@ sub deprecated_functionality { return 1; } +sub log_installed_files { + my ($name, $package, @patterns) = @_; + + my $log = generated_file($package, 'installed-by-' . $name); + open(my $fh, '>', $log); + for my $src (@patterns) { + print $fh "$src\n"; + } + close($fh); + + return 1; +} + 1 # Local Variables: diff --git a/dh_install b/dh_install index 205d4701..a062f9cc 100755 --- a/dh_install +++ b/dh_install @@ -133,8 +133,6 @@ init(options => { "sourcedir=s" => \$dh{SOURCEDIR}, }); -my @installed; - my $srcdir = '.'; $srcdir = $dh{SOURCEDIR} if defined $dh{SOURCEDIR}; @@ -143,6 +141,8 @@ my $missing_files = 0; # PROMISE: DH NOOP WITHOUT install foreach my $package (getpackages()) { + my @installed; + # Look at the install files for all packages to handle # list-missing/fail-missing, but skip really installing for # packages that are not being acted on. @@ -252,51 +252,10 @@ foreach my $package (getpackages()) { } } } -} -if ($dh{LIST_MISSING} || $dh{FAIL_MISSING}) { - # . as srcdir makes no sense, so this is a special case. - if ($srcdir eq '.') { - $srcdir='debian/tmp'; - } - - my @missing; - if ( -f 'debian/not-installed') { - my @not_installed = filearray('debian/not-installed'); - foreach (@not_installed) { - s:^\s*:debian/tmp/: unless m:^\s*debian/tmp/:; - } - # Pretend that these are also installed. - push(@installed, @not_installed); - } - my $installed=join("|", map { - # Kill any extra slashes, for robustness. - y:/:/:s; - s:/+$::; - s:^(\./)*::; - "\Q$_\E\/.*|\Q$_\E"; - } @installed); - $installed=qr{^($installed)$}; - find(sub { - -f || -l || return; - $_="$File::Find::dir/$_"; - if (! /$installed/ && ! excludefile($_)) { - my $file=$_; - $file=~s/^\Q$srcdir\E\///; - push @missing, $file; - } - }, $srcdir); - if (@missing) { - warning "$_ exists in $srcdir but is not installed to anywhere" foreach @missing; - if ($dh{FAIL_MISSING}) { - error("missing files, aborting"); - } - } + log_installed_files('dh_install', $package, @installed); } -if ($missing_files) { - error("missing files, aborting"); -} =head1 LIMITATIONS diff --git a/dh_missing b/dh_missing new file mode 100755 index 00000000..ed3d547e --- /dev/null +++ b/dh_missing @@ -0,0 +1,80 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use File::Find; +use Debian::Debhelper::Dh_Lib; + +init(options => { + "list-missing" => \$dh{LIST_MISSING}, + "fail-missing" => \$dh{FAIL_MISSING}, +}); + +my @installed; + +my $srcdir = '.'; +$srcdir = $dh{SOURCEDIR} if defined $dh{SOURCEDIR}; + +my $missing_files = 0; + +if (!$dh{LIST_MISSING} && !$dh{FAIL_MISSING}) { + exit 0; +} + +# . as srcdir makes no sense, so this is a special case. +if ($srcdir eq '.') { + $srcdir='debian/tmp'; +} + +for my $file (<debian/.debhelper/generated/*/installed-by-*>) { + local $/ = undef; + open(my $fh, '<', $file) or die "could not open $file: $!"; + for my $line (split(/\n/, <$fh>)) { + push(@installed, $line); + } + close($fh); +} + +my @missing; +if ( -f 'debian/not-installed') { + my @not_installed = filearray('debian/not-installed'); + foreach (@not_installed) { + s:^\s*:debian/tmp/: unless m:^\s*debian/tmp/:; + } + # Pretend that these are also installed. + push(@installed, @not_installed); +} +my $installed=join("|", map { + # Kill any extra slashes, for robustness. + y:/:/:s; + s:/+$::; + s:^(\./)*::; + "\Q$_\E\/.*|\Q$_\E"; +} @installed); +$installed=qr{^($installed)$}; +find(sub { + -f || -l || return; + $_="$File::Find::dir/$_"; + if (! /$installed/ && ! excludefile($_)) { + my $file=$_; + $file=~s/^\Q$srcdir\E\///; + push @missing, $file; + } +}, $srcdir); +if (@missing) { + warning "$_ exists in $srcdir but is not installed to anywhere" foreach @missing; + if ($dh{FAIL_MISSING}) { + error("missing files, aborting"); + } +} + +if ($missing_files) { + error("missing files, aborting"); +} + + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 4 +# cperl-indent-level: 4 +# End: diff --git a/t/dh_missing/Makefile b/t/dh_missing/Makefile new file mode 100644 index 00000000..679592a7 --- /dev/null +++ b/t/dh_missing/Makefile @@ -0,0 +1,6 @@ +install: + install -m 755 -d debian/tmp/usr/bin + install -m 644 file-for-foo debian/tmp/usr/bin/file-for-foo + +installmore: install + install -m 644 file-for-foo debian/tmp/usr/bin/file-for-foo-more diff --git a/t/dh_missing/debian/changelog b/t/dh_missing/debian/changelog new file mode 100644 index 00000000..5850f0e2 --- /dev/null +++ b/t/dh_missing/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_missing/debian/compat b/t/dh_missing/debian/compat new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/t/dh_missing/debian/compat @@ -0,0 +1 @@ +10 diff --git a/t/dh_missing/debian/control b/t/dh_missing/debian/control new file mode 100644 index 00000000..48d4de2f --- /dev/null +++ b/t/dh_missing/debian/control @@ -0,0 +1,20 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo + +Package: bar +Architecture: all +Description: package bar + Package bar + +Package: baz +Architecture: all +Description: package baz + Package baz diff --git a/t/dh_missing/debian/foo.install b/t/dh_missing/debian/foo.install new file mode 100644 index 00000000..eddea57c --- /dev/null +++ b/t/dh_missing/debian/foo.install @@ -0,0 +1 @@ +usr/bin/*-for-foo \ No newline at end of file diff --git a/t/dh_missing/dh_missing.t b/t/dh_missing/dh_missing.t new file mode 100755 index 00000000..aa59ec67 --- /dev/null +++ b/t/dh_missing/dh_missing.t @@ -0,0 +1,50 @@ +#!/usr/bin/perl +use strict; +use Test::More; +use File::Basename (); + +# Let the tests be run from anywhere, but current directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +my $TOPDIR = "../.."; +my $rootcmd; + +if ($< == 0) { + $rootcmd = ''; +} +else { + system("fakeroot true 2>/dev/null"); + $rootcmd = $? ? undef : 'fakeroot'; +} + +if (not defined($rootcmd)) { + plan skip_all => 'fakeroot required'; +} +else { + plan(tests => 4); +} + +# Verify dh_missing does not fail when all files are installed. +system("$TOPDIR/dh_clean"); +system("$rootcmd make install"); +system("$rootcmd $TOPDIR/dh_install"); +is(system("$rootcmd $TOPDIR/dh_missing --fail-missing"), 0, 'dh_missing failed'); + +# Verify dh_missing does fail when not all files are installed. +system("$rootcmd $TOPDIR/dh_clean"); +system("$rootcmd make installmore"); +system("$rootcmd $TOPDIR/dh_install"); +system("$rootcmd $TOPDIR/dh_missing --fail-missing"); +isnt($?, -1, 'dh_missing was executed'); +ok(! ($? & 127), 'dh_missing did not die due to a signal'); +my $exitcode = ($? >> 8); +is($exitcode, 2, 'dh_missing exited with exit code 2'); + +system("$rootcmd $TOPDIR/dh_clean"); + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 4 +# cperl-indent-level: 4 +# End: diff --git a/t/dh_missing/file-for-foo b/t/dh_missing/file-for-foo new file mode 100644 index 00000000..8773f398 --- /dev/null +++ b/t/dh_missing/file-for-foo @@ -0,0 +1 @@ +file content \ No newline at end of file -- 2.11.0

