better dep resolver
authorAnas Nashif <anas.nashif@intel.com>
Mon, 23 Jul 2012 19:29:41 +0000 (20:29 +0100)
committerAnas Nashif <anas.nashif@intel.com>
Mon, 23 Jul 2012 19:29:41 +0000 (20:29 +0100)
Change-Id: Id14236857dfef28e524b3ddeb7259383f7ef8f7e

do_expanddeps [new file with mode: 0755]

diff --git a/do_expanddeps b/do_expanddeps
new file mode 100755 (executable)
index 0000000..85ec9c3
--- /dev/null
@@ -0,0 +1,270 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+  unshift @INC, ($::ENV{'BUILD_DIR'} || '/usr/lib/build');
+}
+
+use strict;
+
+use Build;
+
+my ($dist, $rpmdeps, $archs, $configdir, $useusedforbuild);
+
+while (@ARGV)  {
+  if ($ARGV[0] eq '--dist') {
+    shift @ARGV;
+    $dist = shift @ARGV;
+    next;
+  }
+  if ($ARGV[0] eq '--depfile') {
+    shift @ARGV;
+    $rpmdeps = shift @ARGV;
+    next;
+  }
+  if ($ARGV[0] eq '--archpath') {
+    shift @ARGV;
+    $archs = shift @ARGV;
+    next;
+  }
+  if ($ARGV[0] eq '--configdir') {
+    shift @ARGV;
+    $configdir = shift @ARGV;
+    next;
+  }
+  if ($ARGV[0] eq '--useusedforbuild') {
+    shift @ARGV;
+    $useusedforbuild = 1;
+    next;
+  }
+  if ($ARGV[0] eq '--define') {
+    shift @ARGV;
+    my $def = shift @ARGV;
+    Build::define($def);
+    next;
+  }
+  if ($ARGV[0] eq '--with') {
+    shift @ARGV;
+    my $def = shift @ARGV;
+    Build::define("_with_$def --with-$def");
+    next;
+  }
+  if ($ARGV[0] eq '--without') {
+    shift @ARGV;
+    my $def = shift @ARGV;
+    Build::define("_without_$def --without-$def");
+    next;
+  }
+  last;
+}
+$configdir = '.' unless defined $configdir;
+$archs = '' unless defined $archs;
+die("you must specfiy a depfile!\n") unless defined $rpmdeps;
+
+my @extradeps = grep {!/(^|\/)PKGBUILD$/ && !/\.(?:spec|dsc|kiwi)$/} @ARGV;
+my @specs = grep {/(^|\/)PKGBUILD$/ || /\.(?:spec|dsc|kiwi)$/} @ARGV;
+die("can only work with at most one spec\n") if @specs > 1;
+my $spec = $specs[0];
+
+my @archs = split(':', $archs);
+if ($spec && $spec =~ /(^|\/)PKGBUILD$/) {
+  push @archs, 'any' unless grep {$_ eq 'any'} @archs;
+} else {
+  push @archs, 'noarch' unless grep {$_ eq 'noarch'} @archs;
+}
+
+my (%fn, %prov, %req);
+
+my %packs;
+my %repo;
+my %ids;
+
+my %packs_arch;
+my %packs_done;
+open(F, '<', $rpmdeps) || die("$rpmdeps: $!\n");
+# WARNING: the following code assumes that the 'I' tag comes last
+my ($pkgF, $pkgP, $pkgR);
+while(<F>) {
+  chomp;
+  if (/^F:(.*?)-\d+\/\d+\/\d+: (.*)$/) {
+    $pkgF = $2;
+    next if $fn{$1};
+    $fn{$1} = $2;
+    my $pack = $1;
+    $pack =~ /^(.*)\.([^\.]+)$/ or die;
+    push @{$packs_arch{$2}}, $1;
+  } elsif (/^P:(.*?)-\d+\/\d+\/\d+: (.*)$/) {
+    $pkgP = $2;
+    next if $prov{$1};
+    $prov{$1} = $2;
+  } elsif (/^R:(.*?)-\d+\/\d+\/\d+: (.*)$/) {
+    $pkgR = $2;
+    next if $req{$1};
+    $req{$1} = $2;
+  } elsif (/^I:(.*?)-\d+\/\d+\/\d+: (.*)$/) {
+    if ($ids{$1} && $packs_done{$1} && defined($pkgF) && defined($pkgP) && defined($pkgR)) {
+      my $i = $1;
+      my $oldid = $ids{$1};
+      my $newid = $2;
+      if (Build::Rpm::verscmp($oldid, $newid) < 0) {
+        $ids{$i}  = $newid;
+        $fn{$i}   = $pkgF;
+        $prov{$i} = $pkgP;
+        $req{$i}  = $pkgR;
+      }
+    } else {
+      next if $ids{$1};
+      $ids{$1} = $2;
+    }
+    undef $pkgF;
+    undef $pkgP;
+    undef $pkgR;
+  } elsif ($_ eq 'D:') {
+    %packs_done = %ids;
+  }
+}
+close F;
+
+for my $arch (@archs) {
+  $packs{$_} ||= "$_.$arch" for @{$packs_arch{$arch} || []};
+}
+
+# XXX: move to separate tool
+if (!defined($dist) || $dist eq '') {
+  my $rpmarch = (grep {$fn{"rpm.$_"}} @archs)[0];
+  if (!$rpmarch) {
+    $dist = 'default';
+  } else {
+    my $rpmfn = $fn{"rpm.$rpmarch"};
+    if ($rpmfn =~ /^[a-z]+:\/\//) {
+      require File::Temp;
+      my $tmpdir = File::Temp::tempdir('CLEANUP' => 1);
+      $rpmfn =~ s/.*\//$tmpdir\// unless system("$INC[0]/download", $tmpdir, $rpmfn);
+    }
+    my $rpmdist = '';
+    if ($rpmfn =~ /^\// && -e $rpmfn) {
+      my %res = Build::Rpm::rpmq($rpmfn, 1010);
+      $rpmdist = $res{1010}->[0] || '';
+    }
+    $dist = Build::dist_canon($rpmdist, $archs[0]);
+    # need some extra work for sles11 :(
+    if ($dist =~ /^sles11-/) {
+      my %res = Build::Rpm::rpmq($rpmfn, 1049);
+      $dist =~ s/^sles11-/sles11sp2-/ if grep {/^liblzma/} @{$res{1049} || []};
+    }
+  }
+  print STDERR "Warning: distribution not specified, assuming '$dist' (see $configdir).\n";
+}
+
+my $cf = Build::read_config_dist($dist, $archs[0], $configdir);
+$cf->{'warnings'} = 1;
+
+my $dofileprovides = %{$cf->{'fileprovides'}};
+
+for my $pack (keys %packs) {
+  my $r = {};
+  my (@s, $s, @pr, @re);
+  @s = split(' ', $prov{$packs{$pack}} || '');
+  while (@s) {
+    $s = shift @s;
+    next if !$dofileprovides && $s =~ /^\//;
+    if ($s =~ /^rpmlib\(/) {
+      splice(@s, 0, 2);
+      next;
+    }
+    push @pr, $s;
+    splice(@s, 0, 2) if @s && $s[0] =~ /^[<=>]/;
+  }
+  @s = split(' ', $req{$packs{$pack}} || '');
+  while (@s) {
+    $s = shift @s;
+    next if !$dofileprovides && $s =~ /^\//;
+    if ($s =~ /^rpmlib\(/) {
+      splice(@s, 0, 2);
+      next;
+    }
+    push @re, $s;
+    splice(@s, 0, 2) if @s && $s[0] =~ /^[<=>]/;
+  }
+  $r->{'provides'} = \@pr;
+  $r->{'requires'} = \@re;
+  $repo{$pack} = $r;
+}
+
+
+#######################################################################
+
+sub print_rpmlist
+{
+  for (@_) {
+    #print "$_ $fn{$packs{$_}}\n";
+    print "$_\n" if exists $ids{$packs{$_}};
+  }
+}
+
+if ($useusedforbuild) {
+  die("Need a specfile/dscfile for --usedforbuild\n") unless defined $spec;
+  local *F;
+  open(F, '<', $spec) || die("$spec: $!\n");
+  my @usedforbuild;
+  my @buildrequires;
+  while(<F>) {
+    chomp;
+    if (/^#\s*usedforbuild\s*(.*)$/) {
+      push @usedforbuild, split(' ', $1);
+    }
+    if (/^buildrequires:\s*(.*)$/i) {
+      push @buildrequires, split(' ', $1);
+    }
+  }
+  close F;
+  @usedforbuild = @buildrequires unless @usedforbuild;
+  @usedforbuild = Build::unify(@usedforbuild) if @usedforbuild;
+  my @errors;
+  for (@usedforbuild) {
+    push @errors, "package $_ not found" unless $packs{$_} && $fn{$packs{$_}};
+  }
+  if (@errors) {
+    print STDERR "expansion error\n";
+    print STDERR "  $_\n" for @errors;
+    exit(1);
+  }
+  print_rpmlist(@usedforbuild);
+  exit(0);
+}
+
+#######################################################################
+
+my ($packname, $packvers, $subpacks, @packdeps);
+$subpacks = [];
+
+if ($spec) {
+  my $d;
+  if ($spec =~ /\.kiwi$/) {
+    # just set up kiwi root for now
+    $d = {
+      'deps' => [ 'kiwi', 'zypper', 'createrepo', 'squashfs' ],
+      'subpacks' => [],
+    };
+  } else {
+    $d = Build::parse($cf, $spec);
+  }
+  $packname = $d->{'name'};
+  $packvers = $d->{'version'};
+  $subpacks = $d->{'subpacks'};
+  @packdeps = @{$d->{'deps'} || []};
+  push(@packdeps, @{$d->{'prereqs'}}) if $d->{'prereqs'};
+}
+
+Build::readdeps($cf, undef, \%repo);
+
+#######################################################################
+
+my @bdeps = Build::get_build($cf, $subpacks, @packdeps, @extradeps);
+
+if (!shift @bdeps) {
+  print STDERR "expansion error\n";
+  print STDERR "  $_\n" for @bdeps;
+  exit(1);
+}
+
+print_rpmlist(@bdeps);