[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#316283: warn about intra-source circular dependencies



Hi Lintian maintainers,

On Wed, Jun 29, 2005 at 10:23:48PM +0200, Bill Allombert wrote:
> I would like to propose that Lintian emits a warning when a source package
> (or change files) include circular dependencies between the generated
> packages. 

I would like to have this lintian warning proposed by Bill Allombert
too. I started to code a litte, but didn't manage to work out how to put
my code into a form that makes it usable as a lintian check. Thus I do
appreciate any comment on how to achieve that.

The attached perl script is an example of a very simple circular
intra-source dependency check. It takes a .changes file as parameter,
decodes which binary package files are involved, decodes their
dependencies and recursively checks for each of them, whether they can
be satisfied by the other binary packages and whether this would
introduce a circular dependency.

Please note that I intentionally decided to check the dependencies of
the binary packages, and not the debian/control file in the source
package. This way the script is able to discover circular dependencies
where ${shlibs:Depends} is involved. This kind of somewhat hidden
circular dependencies occured to me more than once, and I would love it,
if lintian could warn me about it.

At the moment the script ignores the versions in dependencies and treats
alternative dependencies as single, non-alternative dependencies.

I also attached a simple package specifying explicitly circular
dependencies. I used it for testing and verifying my script.

Regards
  Micha
#! /usr/bin/perl -I /usr/share/lintian/lib
#
# Copyright (C) 2007 Micha Lenk
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.

package Lintian::checkcyclicdep;
use strict;
use Util;
use Dep;

my @packages;
our $dependencies;
our $DEBUG = 0;

my $changesfile = $ARGV[0];
if ($changesfile !~ /\.changes$/) {
	print "Syntax: ./cd-check.pl <.changes-file>\n";
	exit -1;
}
my $changesdir = $changesfile;
$changesdir =~ s/[^\/]+\.changes//;
print "parsing $changesfile...\n" if $DEBUG > 0;
open(my $changesfd, "<$changesfile") or die "Can't open file $changesfile for reading: $!";
my @changes = parse_dpkg_control($changesfd);
close($changesfd);

sub find_loop {
	my $start_package = shift;	# the package
	my $deps = shift;		# pointer to dependencies of "the package"
	my @deps = @$deps;
	my @trace = @_;			# trace of previous packages
	my $result = 0;
	print "DEBUG: find_loop() called for package \033[1;31m$start_package\033[0m with trace ".join(' -> ', @trace).
	      "\n       and dependencies \033[1;33m".Dep::unparse($deps)."\033[0m\n" if $DEBUG > 0;
	my $predicate = shift(@deps);
	print "\033[0;34mDEBUG: predicate: $predicate\n\033[0m" if $DEBUG > 1;
	if ($predicate eq 'PRED') {
		my $leaf = shift(@deps);
		print "\033[0;34mDEBUG: leaf: $leaf\n\033[0m" if $DEBUG > 1;
		foreach my $candidate (@trace) {
			if ($leaf eq $candidate) {
				print "LOOP FOUND: ".join(' -> ', (@trace, $start_package, $trace[0]))."\n";
				$result = 1;
			}
		}
		if ($result == 0 and defined $dependencies->{$leaf}) {
			$result = find_loop($leaf, $dependencies->{$leaf}, (@trace, $start_package));
		}
	} else {
		foreach my $subdep (@deps) {
			$result = find_loop($start_package, $subdep, @trace);
			last if ($result > 0);
		}
	}
	return $result;
}

foreach my $section (@changes) {
	my @files = split(/\n/, $section->{'files'});
	foreach my $files_line (@files) {
		my @files_field = split(/ /, $files_line);
		my $debfile = $files_field[4];
		if ($debfile =~ /.deb$/) {
			print "looking at file $changesdir$debfile:\n" if $DEBUG > 0;
			my $control = get_deb_info($changesdir.$debfile);
			push @packages, $control->{'package'};
			$dependencies->{$control->{'package'}} = Dep::parse($control->{'depends'});
		}
	}
}

printf "We have %u packages to check.\n", $#packages+1 if $DEBUG > 0;
my $result = 0;
foreach my $package (@packages) {
	print "Checking package $package: \n" if $DEBUG > 0;
	$result++ if find_loop($package, $dependencies->{$package}, ()) != 0;
	print "\n" if $DEBUG > 0;
}
exit $result;
Format: 1.0
Source: cyclic-package
Version: 0.1
Binary: cyclic-package-foo, cyclic-package-bar, cyclic-package-fuzz
Maintainer: Micha Lenk <micha@lenk.info>
Architecture: all
Standards-Version: 3.7.2
Build-Depends: debhelper (>= 5)
Files: 
 f26fc2ba5329bd96541ca8a14682c65b 1656 cyclic-package_0.1.tar.gz

Attachment: cyclic-package_0.1.tar.gz
Description: Binary data

Attachment: signature.asc
Description: Digital signature


Reply to: