Package: lintian
Severity: wishlist
Tags: patch
X-Debbugs-Cc: de...@debian.org

Hi,

I would like lintian to complain a bit more about Replaces.

Correct uses of Replaces
========================

The most common way to use Replaces is matching it up with Breaks as
this is recommeded by policy. Another use (also detailed by policy) is
matching it up with Conflicts. A lesser known, but also frequent use
(thanks to David Kalnischkies) is combining versioned Replaces with
precluding Depends.

I want lintian to not moan about any of these.

Debatable uses of Replaces
==========================

Sometimes, Replaces are used with a << version constraint but without
matching them up with Breaks nor Conflicts. This can be useful for
taking over non-essential files from a package (e.g. splitting
documentation from a library). Such cases are still broken if you try to
reinstall the replaced package, but that's not a frequent use and having
less Breaks is beneficial to upgrade paths.

I think it is best for lintian to not moan about any of these unless we
grow consensus that we need to do something about it.

Bad uses of Replaces
====================

The remaining Replaces are thus unversioned and not matched up with
Breaks nor Conflicts. In these case, one could remove the replaced
package and later install it again. While the janitor is able to
eventually delete versioned Replaces, it cannot assist with cleaning up
unversioned ones. Finally, Replaces pose a vital role in the /usr-merge
transition as they can be broken when moving files from / to /usr, so we
want to reduce the use of Replaces to the cases that really need them.

For these reasons, I think that this third class of Replaces really is
harmful enough to the project that it is worth fixing them. In a lot of
cases, I expect that these Replaces are leftovers from the last decade
and we can probably just drop them. In other cases, we can add a version
restriction and improve reasoning about it.

I hope you agree with this reasoning. I've discussed this with a number
of participants on the Debian Reunion Hamburg 2023 and with some people
on IRC. I think what I am presenting here is close to consensus.

I'm also attaching a patch to implement the proposed check.
Unfortunately, neither me nor gregoa nor carnil were able to please
perlcritic (which for some reason is complaining about unrelated code
and we couldn't understand what it is complaining about), so this patch
currently fails one test.  Would you be able to figure out why
perlcritic is mad at this patch?

Thanks in advance

Helmut
diff -Nru lintian-2.116.3/debian/changelog lintian-2.116.3+nmu1/debian/changelog
--- lintian-2.116.3/debian/changelog    2023-02-05 09:10:20.000000000 +0100
+++ lintian-2.116.3+nmu1/debian/changelog       2023-05-24 08:21:25.000000000 
+0200
@@ -1,3 +1,10 @@
+lintian (2.116.3+nmu1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * New tag unguarded-replaces: Complain about unversiond Replaces that
+    are matched with neither Breaks nor Conflicts. (Closes: #-1)
+
+ -- Helmut Grohne <hel...@subdivi.de>  Wed, 24 May 2023 08:21:25 +0200
+
 lintian (2.116.3) unstable; urgency=medium
 
   The "FFP3 (Fixing False Positives, Three Small Changes)" Release.
diff -Nru lintian-2.116.3/lib/Lintian/Check/Fields/PackageRelations.pm 
lintian-2.116.3+nmu1/lib/Lintian/Check/Fields/PackageRelations.pm
--- lintian-2.116.3/lib/Lintian/Check/Fields/PackageRelations.pm        
2022-07-02 15:47:11.000000000 +0200
+++ lintian-2.116.3+nmu1/lib/Lintian/Check/Fields/PackageRelations.pm   
2023-05-24 08:13:03.000000000 +0200
@@ -219,6 +219,15 @@
                     && !$VIRTUAL_PACKAGES->recognizes($d_pkg)
                     && !$replaces->satisfies($part_d_orig));
 
+                $self->hint('unguarded-replaces', $part_d_orig)
+                  if ( $field eq 'Replaces'
+                    && !$d_version->[0]
+                    && !any {
+                      any {
+                        $_->satisfies($part_d_orig)
+                      } $processable->relation($_)
+                    } qw(Breaks Conflicts));
+
                 $self->hint('conflicts-with-version', $part_d_orig)
                   if ($field eq 'Conflicts' && $d_version->[0]);
 
diff -Nru 
lintian-2.116.3/t/recipes/checks/fields/package-relations/fields-depends-general/eval/hints
 
lintian-2.116.3+nmu1/t/recipes/checks/fields/package-relations/fields-depends-general/eval/hints
--- 
lintian-2.116.3/t/recipes/checks/fields/package-relations/fields-depends-general/eval/hints
 2022-12-22 12:47:19.000000000 +0100
+++ 
lintian-2.116.3+nmu1/t/recipes/checks/fields/package-relations/fields-depends-general/eval/hints
    2023-05-24 08:21:25.000000000 +0200
@@ -28,3 +28,4 @@
 fields-depends-general (binary): conflicts-with-dependency Depends conflict-dep
 fields-depends-general (binary): breaks-without-version package-without-version
 fields-depends-general (binary): binary-package-depends-on-toolchain-package 
Depends: debhelper
+fields-depends-general (binary): unguarded-replaces Replaces: 
replaced-wo-version
diff -Nru lintian-2.116.3/tags/u/unguarded-replaces.tag 
lintian-2.116.3+nmu1/tags/u/unguarded-replaces.tag
--- lintian-2.116.3/tags/u/unguarded-replaces.tag       1970-01-01 
01:00:00.000000000 +0100
+++ lintian-2.116.3+nmu1/tags/u/unguarded-replaces.tag  2023-05-24 
08:20:59.000000000 +0200
@@ -0,0 +1,10 @@
+Tag: unguarded-replaces
+Severity: warning
+Check: fields/package-relations
+See-Also: debian-policy 7.6
+Explanation: This package declares that replaces another package without
+ further restrictions. If the package being replaced is supposed to go
+ away entirely, an unversioned Replaces declaration should be combined with
+ an unversioned Conflicts declaration. If files are being replaced in an old
+ version, the Replaces declaration should include a (<< ...) version
+ constraint.

Reply via email to