tags 222652 patch
thanks

Hello,

This patch implements the third solution.

It solves some of the Lintian package-has-a-duplicate-relation warnings
(http://lintian.debian.org/reports/Tpackage-has-a-duplicate-relation.html).

It only simplifies the Depends field, but I think it should be sufficient.
(I assumed there is no automatic variables for the other dependency
fields; this can be changed easily)

It does not simplify the dependencies between different fields (e.g. a
package can Pre-Depends on foo and also Depends on foo).

It does not simplify the dependencies with archs and ORed lists (e.g.
Depends: foo | bar, bar (>= 2) could be simplified in Depends: bar (>= 2)).

The simplification is done when the control file is written, after the
variables were substituted (in outputclose).

I tested the simplify_deps subroutine on an unstable_main_binary-i386_Packages.


Kind Regards,
-- 
Nekral
Index: controllib.pl
===================================================================
--- controllib.pl       (révision 239)
+++ controllib.pl       (copie de travail)
@@ -168,6 +168,7 @@
           $v =~ s/\s*,\s*$//;
        }
         $v =~ s/\$\{\}/\$/g;
+        $v = simplify_deps($f, $v);
         print("$f: $v\n") || &syserr("write error on control data");
     }
 
@@ -409,4 +410,157 @@
     }
 }
 
+# Simplify a dependency line by merging the dependencies on the same
+# package.
+sub simplify_deps {
+    my $dep_field=shift;
+    my $dep_line=shift;
+
+    return $dep_line unless ($dep_field eq "Depends");
+
+    my $dep_list = parsedep($dep_line, 1, 0);
+
+    # %pkg_dep keeps the versionned dependency associated with each package
+    my %pkg_dep;
+    # When the dependency can't be merged, it is pushed in @new_dep_list.
+    # Dependencies with a list of archs or an OR list are also push in
+    # this array.
+    my @new_dep_list;
+    foreach my $dep_and (@$dep_list) {
+        my $new_dep_and;
+        if (scalar(@$dep_and) > 1) {
+            # ORed list
+            push @new_dep_list, $dep_and;
+        } else {
+            my $alternate = [EMAIL PROTECTED];
+            my ($package, $relation, $version, $arch_list)= @{$alternate};
+            if (scalar(@$arch_list)) {
+                # Dependency with a list of archs
+                push @new_dep_list, $dep_and;
+            } else {
+                # Merge this dependency with the previous dependency of
+                # this package
+                my @versioned_deps = ($relation, $version);
+                my @new_deps = merge_depends($pkg_dep{$package},
+                                             [EMAIL PROTECTED]);
+                if ((scalar @new_deps)>1) {
+                    # The dependency could not be merged. Push both
+                    # dependencies in @new_dep_list.
+                    delete $pkg_dep{$package};
+                    my @arch_list = ();
+                    foreach (@new_deps) {
+                        my @new_alternate = ($package, [EMAIL PROTECTED],
+                                             [EMAIL PROTECTED], [EMAIL 
PROTECTED]);
+                        my @or_list = ([EMAIL PROTECTED]);
+                        push @new_dep_list, [EMAIL PROTECTED];
+                    }
+                } else {
+                    $pkg_dep{$package} = $new_deps[0];
+                }
+            }
+        }
+    }
+    # Push the merged dependencies
+    foreach my $pkg (keys %pkg_dep) {
+        my @versioned_deps = @{$pkg_dep{$pkg}};
+        my @arch_list = ();
+        my @new_alternate = ($pkg, $versioned_deps[0],
+                             $versioned_deps[1], [EMAIL PROTECTED]);
+        my @or_list = ([EMAIL PROTECTED]);
+        push @new_dep_list, [EMAIL PROTECTED];
+    }
+
+    return showdep([EMAIL PROTECTED], 1);
+}
+
+# Merge two dependencies on the same package.
+# The dependencies are provided as a reference to a (relation, version)
+# array.
+# 
+# Return a reference to an array.
+# If the dependencies can be merged, this array will have one element: a
+# reference to an (relation, version) array.
+sub merge_depends {
+    my $versioned_dep1 = shift;
+    my $versioned_dep2 = shift;
+    my ($relation1, $version1) = @$versioned_dep1;
+    my ($relation2, $version2) = @$versioned_dep2;
+
+    my @result = ();
+    return $versioned_dep2 if (   not defined $versioned_dep1
+                               or not defined $relation1);
+    return $versioned_dep1 if (   not defined $versioned_dep2
+                               or not defined $relation2);
+
+    my @default = ($versioned_dep1, $versioned_dep2);
+
+    if ($relation1 =~ m/</ and $relation2 =~ m/</) {
+        if (cmp_version($version1, $version2) < 0) {
+            @result = ($relation1, $version1);
+        } elsif ($version1 eq $version2) {
+            if ($relation1 eq "<<" or $relation2 eq "<<") {
+                @result = ("<<", $version1);
+            } else {
+                @result = ("<=", $version1);
+            }
+        } else {
+            @result = ($relation2, $version2);
+        }
+        return ([EMAIL PROTECTED]);
+    } elsif ($relation1 eq "=" or $relation2 eq "=") {
+        # Make sure the "=" relation is the first dependency
+        if ($relation2 eq "=") {
+            ($relation1, $relation2) = ($relation2, $relation1);
+            ($version1, $version2) = ($version2, $version1);
+        }
+
+        my $cmp = cmp_version($version1, $version2);
+        # Detect unsatifiable conditions
+        if ($relation2 eq "<<") {
+            return @default if ($cmp >= 0);
+        } elsif ($relation2 eq "<=" or $relation2 eq "<") {
+            return @default if ($cmp > 0);
+        } elsif ($relation2 eq "=") {
+            return @default if ($cmp != 0);
+        } elsif ($relation2 eq ">=" or $relation2 eq ">") {
+            return @default if ($cmp < 0);
+        } elsif ($relation2 eq ">>") {
+            return @default if ($cmp <= 0);
+        } else {
+            return @default;
+        }
+        # Otherwise, just return the dependency on a fixed version
+        @result = ($relation1, $version1);
+        return ([EMAIL PROTECTED]);
+    } elsif ($relation1 =~ m/>/ and $relation2 =~ m/>/) {
+        if (cmp_version($version1, $version2) > 0) {
+            @result = ($relation1, $version1);
+        } elsif ($version1 eq $version2) {
+            if ($relation1 eq ">>" or $relation2 eq ">>") {
+                @result = (">>", $version1);
+            } else {
+                @result = (">=", $version1);
+            }
+        } else {
+            @result = ($relation2, $version2);
+        }
+        return ([EMAIL PROTECTED]);
+    } else {
+        # Either unsatisfiable or a bounded interval
+        return @default;
+    }
+}
+
+# Compare two package versions.
+# Return an integer less than, equal to, or greater than zero if the first
+# version is found, respectively, to be less than, to match, or be greater
+# than the second one.
+sub cmp_version {
+    my ($v1, $v2) = (shift, shift);
+
+    return 0 if ($v1 eq $v2);
+    system("dpkg", "--compare-versions", $v1, "lt", $v2);
+    return (($? >> 8) != 0)?1:-1;
+}
+
 1;

Reply via email to