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

Re: limitation in build-depends



Matt Zimmerman wrote:
> On Fri, Jan 12, 2001 at 09:39:02AM +0100, Wichert Akkerman wrote:
> > Previously Paul Slootman wrote:
> > > Why doesn't dpkg-buildpackage check the Build-Depends line?
> > Patches are welcome.
> 
> Here is a script I put together recently that does part of what is needed.  It
> takes a list of packages, and checks whether they are installed or provided by
> another package.  What is missing is handling for boolean expressions.

The attached program includes a fairly general subroutine for checking
build-dependancies, and your status parser, and a little bit of code to
call the subroutine and output a list of unmet build deps. It also
returns false if there are unmet build deps. Sample run:

joey@kite:~>perl check_build_deps
Enter build-dependancy line: libc6 (>= 9999.99) | bar [sparc]
Unmet: libc6 (>= 9999.99)
joey@kite:~>perl check_build_deps
Enter build-dependancy line: dpkg (>= 1.7.0), flex, bison, bsdmainutils, groff, libz-dev, libncurses5-dev, libpam-dev, libfreetype6-dev, libpaperg, tetex-bin, debhelper (>= 2.1.8), lynx, libglide2-dev [i386], libglide3-dev [i386]
Unmet: libpam-dev
Unmet: libfreetype6-dev
Unmet: libglide2-dev
Unmet: libglide3-dev
+ exit 1

It handles version number compares and architecture-sepecific
build-dependances, as you can see.

Handling of build-conflicts is left as an exercise for the reader.
Sadly, it's not a straightforeard inversion of the return code of
unmet_build_depends...

-- 
see shy jo
#!/usr/bin/perl -w
use strict;

$|=1;
print "Enter build-dependancy line: ";
my $line=<>;
chomp $line;

# This part could be replaced. Silly little status file parser.
# thanks to Matt Zimmerman.
my %providers;
my %version;
$/ = '';
my $status = "/var/lib/dpkg/status";
open(STATUS, "<$status") || die "$status: $!\n";
while (<STATUS>) {
	next unless /^Status: .*ok installed$/m;

	my ($package) = /^Package: (.*)$/m;
	push @{$providers{$package}}, $package;
	($version{$package}) = /^Version: (.*)$/m;

	if (/^Provides: (.*)$/m) {
		foreach (split(/,\s+/, $1)) {
			push @{$providers{$_}}, $package;
		}
	}
}
close STATUS;

my @unmet=unmet_build_depends($line, \%version, \%providers);
foreach (@unmet) {
	print STDERR "Unmet: $_\n";
}
exit 1 if @unmet;

# This function checks the build dependancies passed in as the first
# parameter. If they are satisfied, returns false. If they are unsatisfied,
# an list of the unsatisfied depends is returned.
#
# Additional parameters that must be passed:
# * A reference to a hash of all "ok installed" the packages on the system,
#   with the hash key being the package name, and the value being the 
#   installed version.
# * A reference to a hash, where the keys are package names, and the
#   value is a true value iff some package installed on the system provides
#   that package (all installed packages provide themselves)
#
# Optionally, the architecture the package is to be built for can be passed
# in as the 4th parameter. If not set, dpkg will be queried for the build
# architecture.
sub unmet_build_depends {
	my $line=shift;
	my %version=%{shift()};
	my %providers=%{shift()};
	my $build_arch=shift || `dpkg --print-architecture`;
	chomp $build_arch;

	my @unmet=();
	foreach my $dep (split(/,\s+/, $line)) {
		my $ok=0;
		my @possibles=();
ALTERNATE:	foreach my $alternate (split(/\s*\|\s*/, $dep)) {
			my ($package, $rest)=split(/\s+/, $alternate, 2);
	
			# Check arch specifications.
			if (defined $rest && $rest=~m/\[(.*?)\]/) {
				my $arches=lc($1);
				my $seen_arch='';
				foreach my $arch (split(' ', $arches)) {
					if ($arch eq $build_arch) {
						$seen_arch=1;
						next;
					}
					elsif ($arch eq "!$build_arch") {
						next ALTERNATE;
					}
					elsif ($arch =~ /!/) {
						# This is equivilant to
						# having seen the current arch,
						# unless the current arch
						# is also listed..
						$seen_arch=1;
					}
				}
				if (! $seen_arch) {
					next;
				}
			}
			
			# This is a possibile way to meet the dependancy.
			# Remove the arch stuff from $alternate.
			$alternate=~s/\s+\[.*?\]//;
			push @possibles, $alternate;
	
			# Check version.
			if (defined $rest && $rest=~m/\((..)\s+(.*?)\)/) {
				my $relation=$1;
				my $version=$2;
				
				if (! exists $version{$package}) {
					# Not installed at all, so fail.
					next;
				}
				else {
					# Compare installed and needed
					# version number.
					system("dpkg", "--compare-versions",
						$version{$package}, $relation,
						 $version);
					if (($? >> 8) != 0) {
						next; # fail
					}
				}
			}
			elsif (! defined $providers{$package}) {
				# It's not a versioned dependancy, and
				# nothing provides it, so fail.
				next;
			}
	
			# If we get to here, the dependancy was met.
			$ok=1;
		}
	
		# If there were no possibilities of meeting this
		# dependancy, it means it is a dep that only applies to
		# other arches.
		if (! $ok && @possibles) {
			# TODO: this could return a more complex
			# data structure instead to save re-parsing.
			push @unmet, join (" | ", @possibles);
		}
	}

	return @unmet;
}

Reply to: