From 292ed284159c7726aa283d7bfb75d3c7a597f0da Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Thu, 27 Oct 2016 14:26:00 +0900 Subject: [PATCH] Recognize Recommends relations of RPMs When there are multiple candidate packages as a result of Provides, the current obs-build gives an error: "have choice for". However, according to http://www.rpm.org/wiki/PackagerDocs/Dependencies , Recommends tells the system to install the corresponding package unless there is a conflict; thus, if there is a package recommended (as described in issue #302), obs-build shall install the recommended package, resolving "have choice for" error. To enable, OBS project should declare: "BuildFlags: UseRecommendsForChoices=1" or "BuildFlags: UseRecommendsForChoices" in its project config. Fixes #302 Signed-off-by: MyungJoo Ham Conflicts: createdirdeps expanddeps Change-Id: I65dc6dd16a6874b7c1ae47932d37c23ec98b9cdf --- Build.pm | 32 ++++++++++++++++++++++++++++++-- createdirdeps | 6 +++--- expanddeps | 28 +++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Build.pm b/Build.pm index 4277c46..e03c3ab 100644 --- a/Build.pm +++ b/Build.pm @@ -585,8 +585,8 @@ sub get_cbinstalls { return @{[]}; } sub readdeps { my ($config, $pkginfo, @depfiles) = @_; - my %requires; + my %recommends; local *F; my %provides; my %pkgconflicts; @@ -597,6 +597,7 @@ sub readdeps { for my $rr (keys %$depfile) { $provides{$rr} = $depfile->{$rr}->{'provides'}; $requires{$rr} = $depfile->{$rr}->{'requires'}; + $recommends{$rr} = $depfile->{$rr}->{'recommends'}; $pkgconflicts{$rr} = $depfile->{$rr}->{'conflicts'}; $pkgobsoletes{$rr} = $depfile->{$rr}->{'obsoletes'}; } @@ -640,7 +641,7 @@ sub readdeps { } my %ss; @ss = grep {!$ss{$_}++} @ss; - if ($s =~ /^(P|R|C|O):(.*)\.(.*)-\d+\/\d+\/\d+:$/) { + if ($s =~ /^(P|R|C|O|r):(.*)\.(.*)-\d+\/\d+\/\d+:$/) { my $pkgid = $2; my $arch = $3; if ($1 eq "P") { @@ -656,6 +657,11 @@ sub readdeps { $pkginfo->{$pkgid}->{'requires'} = \@ss if $pkginfo; next; } + if ($1 eq "r") { + $recommends{$pkgid} = \@ss; + $pkginfo->{$pkgid}->{'recommends'} = \@ss if $pkginfo; + next; + } if ($1 eq "C") { $pkgconflicts{$pkgid} = \@ss; $pkginfo->{$pkgid}->{'conflicts'} = \@ss if $pkginfo; @@ -687,6 +693,7 @@ sub readdeps { } $config->{'providesh'} = \%provides; $config->{'requiresh'} = \%requires; + $config->{'recommendsh'} = \%recommends; $config->{'pkgconflictsh'} = \%pkgconflicts; $config->{'pkgobsoletesh'} = \%pkgobsoletes; makewhatprovidesh($config); @@ -714,6 +721,7 @@ sub writedeps { print $fh "F:$id$url$pkg->{'location'}\n"; print $fh "P:$id".join(' ', @{$pkg->{'provides'} || []})."\n"; print $fh "R:$id".join(' ', @{$pkg->{'requires'}})."\n" if $pkg->{'requires'}; + print $fh "r:$id".join(' ', @{$pkg->{'recommends'}})."\n" if $pkg->{'recommends'}; print $fh "C:$id".join(' ', @{$pkg->{'conflicts'}})."\n" if $pkg->{'conflicts'}; print $fh "O:$id".join(' ', @{$pkg->{'obsoletes'}})."\n" if $pkg->{'obsoletes'}; print $fh "I:$id".getbuildid($pkg)."\n"; @@ -749,6 +757,7 @@ sub forgetdeps { delete $config->{'providesh'}; delete $config->{'whatprovidesh'}; delete $config->{'requiresh'}; + delete $config->{'recommendsh'}; delete $config->{'pkgconflictsh'}; delete $config->{'pkgobsoletesh'}; } @@ -866,6 +875,7 @@ sub expand { my $whatprovides = $config->{'whatprovidesh'}; my $requires = $config->{'requiresh'}; + my $recommends = $config->{'recommendsh'}; my %xignore = map {substr($_, 1) => 1} grep {/^-/} @p; my @directdepsend; @@ -975,6 +985,22 @@ sub expand { last; } } + if (@q > 1 && $config->{"buildflags:userecommendsforchoices"} && @{$recommends->{$p} || []} > 0) { + my @recommendedq; + my $i; + + for my $iq (@q) { + for my $rpkg (@{$recommends->{$p}}) { + if ($rpkg =~ /$iq/) { + push @recommendedq, $iq; + } + } + } + if (@recommendedq > 0) { + print "recommended [@recommendedq] among [@q]\n" if $expand_dbg; + @q = @recommendedq; + } + } if (@q > 1) { if ($r ne $p) { push @error, "have choice for $r needed by $p: @q"; @@ -1020,6 +1046,7 @@ sub order { my ($config, @p) = @_; my $requires = $config->{'requiresh'}; + my $recommends = $config->{'recommendsh'}; my $whatprovides = $config->{'whatprovidesh'}; my %deps; my %rdeps; @@ -1117,6 +1144,7 @@ sub add_all_providers { my ($config, @p) = @_; my $whatprovides = $config->{'whatprovidesh'}; my $requires = $config->{'requiresh'}; + my $recommends = $config->{'recommendsh'}; my %a; for my $p (@p) { for my $r (@{$requires->{$p} || [$p]}) { diff --git a/createdirdeps b/createdirdeps index 280e4f5..b50739f 100755 --- a/createdirdeps +++ b/createdirdeps @@ -51,7 +51,7 @@ my %old; if (defined($oldfile) && open(F, '<', $oldfile)) { while () { chomp; - $old{$1} = $_ if /^([PRCOI]:[^ ]+): /; + $old{$1} = $_ if /^([PRrCOI]:[^ ]+): /; } close F; } @@ -78,14 +78,14 @@ for my $dir (@ARGV) { next if $seen{$idx}; $seen{$idx} = 1; print "F:$idx: $path\n"; - for (qw{P R C O I}) { + for (qw{P R r C O I}) { print $old{"$_:$idx"}."\n" if $old{"$_:$idx"}; } next; } } } - my $q = Build::query($path, 'addselfprovides' => 1, 'conflicts' => 1, 'evra' => 1, 'buildtime' => 1, 'alldeps' => 1); + my $q = Build::query($path, 'addselfprovides' => 1, 'conflicts' => 1, 'evra' => 1, 'buildtime' => 1, 'weakdeps' => 1); next unless $q && defined($q->{'name'}) && defined($q->{'arch'}) && defined($q->{'version'}); my $idx = "$q->{'name'}.$q->{'arch'}-$id"; next if $seen{$idx}; diff --git a/expanddeps b/expanddeps index 2dcd3eb..19d9e7e 100755 --- a/expanddeps +++ b/expanddeps @@ -126,7 +126,7 @@ if (defined($dist) && $dist ne '') { $binarytype = $cf->{'binarytype'} if $cf->{'binarytype'} && $cf->{'binarytype'} ne 'UNDEFINED'; } -my (%fn, %prov, %req, %con, %obs); +my (%fn, %prov, %req, %rec, %con, %obs); my %packs; my %repo; @@ -170,7 +170,7 @@ my %exportfilters = %{$cf->{'exportfilter'}}; open(F, '<', $rpmdeps) || die("$rpmdeps: $!\n"); # WARNING: the following code assumes that the 'I' tag comes last -my ($pkgF, $pkgP, $pkgR, $pkgC, $pkgO); +my ($pkgF, $pkgP, $pkgR, $pkgr, $pkgC, $pkgO); my $verscmp = \&Build::Rpm::verscmp; @@ -210,6 +210,8 @@ while() { $pkgR = $2; next if $req{$1}; $req{$1} = $2; + } elsif (/^r:(.*?)-\d+\/\d+\/\d+: (.*)$/) { + $pkgr = $2; } elsif (/^C:(.*?)-\d+\/\d+\/\d+: (.*)$/) { $pkgC = $2; next if $con{$1}; @@ -241,9 +243,11 @@ while() { $fn{$i} = $pkgF; $prov{$i} = $pkgP; delete $req{$i}; + delete $rec{$i}; delete $con{$i}; delete $obs{$i}; $req{$i} = $pkgR; + $rec{$i} = $pkgr; $con{$i} = $pkgC if defined $pkgC; $obs{$i} = $pkgO if defined $pkgO; } else { @@ -253,6 +257,7 @@ while() { undef $pkgF; undef $pkgP; undef $pkgR; + undef $pkgr; undef $pkgC; undef $pkgO; } elsif ($_ eq 'D:') { @@ -267,7 +272,7 @@ for my $arch (@archs) { for my $pack (keys %packs) { my $r = {}; - my (@s, $s, @pr, @re, @co, @ob); + my (@s, $s, @pr, @re, @rc, @co, @ob); @s = split(' ', $prov{$packs{$pack}} || ''); while (@s) { $s = shift @s; @@ -300,6 +305,22 @@ for my $pack (keys %packs) { splice(@s, 0, 2); } } + @s = split(' ', $rec{$packs{$pack}} || ''); + while (@s) { + $s = shift @s; + next if !$dofileprovides && $s =~ /^\//; + if ($s =~ /^rpmlib\(/) { + splice(@s, 0, 2); + next; + } + push @rc, $s; + while (@s && $s[0] =~ /^[\(<=>|]/) { + $rc[-1] .= " $s[0] $s[1]"; + $rc[-1] =~ s/ \((.*)\)/ $1/; + $rc[-1] =~ s/(<|>){2}/$1/; + splice(@s, 0, 2); + } + } @s = split(' ', $con{$packs{$pack}} || ''); while (@s) { $s = shift @s; @@ -326,6 +347,7 @@ for my $pack (keys %packs) { } $r->{'provides'} = \@pr; $r->{'requires'} = \@re; + $r->{'recommends'} = \@rc; $r->{'conflicts'} = \@co; $r->{'obsoletes'} = \@ob; $repo{$pack} = $r; -- 2.7.4