From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Date: Tue, 12 Apr 2005 06:13:21 +0400 From: Alexey Tourbin To: devel@altlinux.ru Message-ID: <20050412021321.GQ3309@solemn.turbinal.org> Mail-Followup-To: devel@altlinux.ru Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="+nLR7g8KNfrRqv5t" Content-Disposition: inline Subject: [devel] buildreq2 X-BeenThere: devel@altlinux.ru X-Mailman-Version: 2.1.5 Precedence: list Reply-To: ALT Devel discussion list List-Id: ALT Devel discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Apr 2005 02:14:22 -0000 Archived-At: List-Archive: List-Post: --+nLR7g8KNfrRqv5t Content-Type: multipart/mixed; boundary="WTbgq2twYBxfsYA6" Content-Disposition: inline --WTbgq2twYBxfsYA6 Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Content-Transfer-Encoding: quoted-printable =FA=C4=D2=C1=D7=D3=D4=D7=D5=CA=D4=C5. =F0=D2=C5=C4=D7=C1=D2=C9=D4=C5=CC=D8=CE=C1=D1 =D7=C5=D2=D3=C9=D1 buildreq2 = =C7=CF=D4=CF=D7=C1 =C9 =C9=D3=D0=D9=D4=C1=CE=C1 =D7 =C2=CF=C5=D7=D9=C8 =D5= =D3=CC=CF=D7=C9=D1=C8. =E9=DA =D4=C5=CB=D5=DD=C9=C8 =CE=C5=C4=CF=D3=D4=C1=D4=CB=CF=D7: 1) =D3=D4=C1=C4=C9=C0 -bi =D0=CF=CB=C1 =D5=CB=C1=DA=C1=D4=D8 =CE=C5=CC=D8= =DA=D1; =CE=CF =CD=CE=C5 =CF=DE=C5=CE=D8 =CE=C5 =CE=D2=C1=D7=C9=D4=D3=D1, = =DE=D4=CF =D7 find-requires =D7 =C2=C5=DA=D5=D3=CC=CF=D7=CE=CF=CD =D0=CF=D2=D1=C4=CB=C5 = =DA=C1=D0=D5=D3=CB=C1=C5=D4=D3=D1 python =CE=C1 =D7=D3=C5 *.so =C6=C1=CA=CC= =D9. 2) substitute.d =D4=C9=D0=C1 s/libdb4.3-devel/libdb4-devel/ =D0=CF=CB=C1 = =CE=C5 =D2=C1=C2=CF=D4=C1=C5=D4. =EF=D3=D4=C1=CC=D8=CE=CF=C5 =D7=D3=A3 =D2=C1=C2=CF=D4=C1=C5=D4. =F3=CF=C2=D2=C1=CC =D3=C5=C7=CF=C4=CE=D1 =D3 =CE=C9=CD =CE=C5=D3=CB=CF=CC= =D8=CB=CF =D0=C1=CB=C5=D4=CF=D7: $ grep -A1 buildreq2 *.spec(.m-1) perl-bignum.spec:# Automatically added by buildreq2 on Tue Apr 12 2005 perl-bignum.spec-BuildRequires: perl-Math-BigRat perl-YAML perl-devel -- perl-Math-BigInt.spec:# Automatically added by buildreq2 on Tue Apr 12 2005 perl-Math-BigInt.spec-BuildRequires: perl-YAML perl-devel -- perl-Math-BigRat.spec:# Automatically added by buildreq2 on Tue Apr 12 2005 perl-Math-BigRat.spec-BuildRequires: perl-Math-BigInt perl-YAML perl-devel -- perl-Unicode-Normalize.spec:# Automatically added by buildreq2 on Tue Apr 1= 2 2005 perl-Unicode-Normalize.spec-BuildRequires: perl-devel perl-unicore $ =F0=D2=CF=C2=D5=CA=D4=C5. :) --WTbgq2twYBxfsYA6 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=buildreq2 Content-Transfer-Encoding: quoted-printable #!/usr/bin/perl # vim: ts=3D4 sw=3D4 use 5.006; use strict; use sort 'stable'; use File::Basename qw(basename); my $progname =3D basename $0; ################################################################ sub strace (@) { pipe my ($r, $w) or die "$progname: pipe: $!\n"; my $pid =3D fork; defined $pid or die "$progname: fork: $!\n"; if ($pid) { close $w; return ($pid, $r); } else { close $r; use Fcntl qw(F_SETFD); fcntl $w, F_SETFD, 0; my $out =3D "/dev/fd/" . fileno($w); my @strace =3D (qw(strace -kqfF -e trace=3Dfile -o) =3D> $out =3D> "--"); exec @strace, @_; die "$progname: exec strace: $!\n"; } } ################################################################ package SPP; sub TIEHANDLE { my ($class, $fh) =3D @_; return bless { fh =3D> $fh, trace =3D> {} } =3D> $class; } sub READLINE { my $self =3D shift; my $fh =3D $$self{fh}; my $trace =3D $$self{trace}; while (1) { local $_ =3D <$fh> or return; if (s/^(\d+)(\s+)(.*)\s+$/$1$2$3/) { die "$progname: pid $1 unfinished twice\n" if defined $$trace{$1}; $$trace{$1} =3D $_; next; } elsif (s/^(\d+)\s+<\.\.\.\s+\w+\s+resumed>//) { die "$progname: pid $1 resumed without being unfinished\n" if not defined $$trace{$1}; $_ =3D delete($$trace{$1}) . $_; } return $_; } } package main; ################################################################ sub filereq (@) { my ($pid, $fd) =3D &strace; tie local *FH, SPP =3D> $fd; my %files; local $_; while () { $files{$1}++ if m#^\d+\s+\w+[(]"(/.+?)"#; } untie *FH; close $fd; waitpid($pid, 0) =3D=3D $pid or die "$progname: waitpid: $!\n"; $? =3D=3D 0 or die "$progname: strace exit status $?\n"; return sort grep { -f } keys %files; } ################################################################ use RPM::Database; my $rpmdb =3D RPM::Database->new or die "$progname: rpmdb: $RPM::err\n"; my %qR; sub qR ($) { my $name =3D shift; my $deps =3D $qR{$name} ||=3D $$rpmdb{$name} && $$rpmdb{$name}{REQUIRENAME= }; return wantarray ? @$deps : scalar @$deps; } my %qP; sub qP ($) { my $name =3D shift; my $deps =3D $qP{$name} ||=3D $$rpmdb{$name} && $$rpmdb{$name}{PROVIDES}; return wantarray ? @$deps : scalar @$deps; } my %qwP; sub qwP ($) { my $name =3D shift; my $deps =3D $qwP{$name} ||=3D [ map { $$_{NAME} } $rpmdb->find_what_provi= des($name) ]; return wantarray ? @$deps : scalar @$deps; } ################################################################ sub packagereq (@) { my $bad =3D qr{^/etc/rpm/macros[.]d/|^/usr/share/aclocal/}; # hardcoded my @files =3D grep { not /$bad/ } &filereq; my %packages; foreach my $file (@files) { my $hdr =3D $rpmdb->find_by_file($file); next unless $hdr; my $package =3D $$hdr{NAME}; next unless $package; push @{$packages{$package}}, $file; } return \%packages; } sub buildreq ($) { my $spec =3D shift; my @rpmargs =3D ("--nodeps", "--define", "__buildreqs 1", "--define", "__n= procs 1"); return packagereq("rpm", "-bc", @rpmargs, "--", $spec); } ################################################################ sub expand (@) { my %packages =3D my %expanded =3D map { $_ =3D> 1 } @_; do { %packages =3D %expanded; my @packages =3D sort keys %packages; foreach my $pkg (@packages) { my @req =3D qR($pkg) or next; foreach my $req (@req) { next if $expanded{$req}; if (exists $$rpmdb{$req}) { print "$pkg -> $req\n"; $expanded{$req} =3D 1; next; } else { my @prov =3D qwP($req); next unless @prov; next if grep { $expanded{$_} } @prov; @prov =3D reverse sort @prov; print "warning: $req provided by @prov\n" if @prov > 1; next if @prov > 1; print "$pkg -> $req -> $prov[0]\n"; $expanded{$prov[0]} =3D 1; } } } } while keys(%expanded) > keys(%packages); return sort keys %expanded; } sub intersect ($$) { my ($aref1, $aref2) =3D @_; my @sect; foreach my $e1 (@$aref1) { foreach my $e2 (@$aref2) { push @sect, $e1 if $e1 eq $e2; } } return unless @sect; @sect =3D sort { length($a) <=3D> length($b) } sort @sect; return wantarray ? @sect : $sect[0]; } sub squeeze (@) { my @packages =3D sort { qR($a) <=3D> qR($b) } sort @_; my %packages =3D map { $_ =3D> 1 } @packages; PREY: foreach my $p0 (@packages) { my @req0 =3D qR($p0); my @prov0 =3D qP($p0); RAPTOR:=09 foreach my $pN (@packages) { next PREY unless $packages{$p0}; next RAPTOR if $p0 eq $pN; my @reqN =3D qR($pN); my @provN =3D qP($pN); my $do =3D intersect [ $p0 ] =3D> \@reqN; my $dox =3D intersect \@prov0 =3D> \@reqN; my $undo =3D intersect [ $pN ] =3D> \@req0; my $undox =3D intersect \@provN =3D> \@req0; if ($do and (not ($undo or $undox) or $packages{$pN})) { print "$p0 < $pN\n"; $packages{$p0} =3D 0; next PREY; } if ($dox and (not ($undo or $undox) or $packages{$pN})) { print "$p0 < $dox < $pN\n"; $packages{$p0} =3D 0; next PREY; } } } return sort grep { $packages{$_} } keys %packages; } ################################################################ sub optimize (@) { my @packages =3D @_; print "\tExpanding...\n"; @packages =3D expand(@packages); print "BuildRequires: @packages\n"; print "\tSqueezing...\n"; @packages =3D squeeze(@packages); print "BuildRequires: @packages\n"; my $bad =3D qr{^glibc-core-|^rpm-build$|^ccache$|^hostinfo$}; # hardcoded my @new; foreach my $pkg (@packages) { if ($pkg =3D~ $bad) { print "Removing $pkg...\n"; } else { push @new, $pkg; } } print "BuildRequires: @new\n" if @new < @packages; return @new;=09 } sub explain ($) { use Data::Dumper qw(Dumper); local $Data::Dumper::Terse =3D 1; local $Data::Dumper::Useqq =3D 1; local $Data::Dumper::Indent =3D 1; print Dumper(@_); return shift; } ################################################################ sub alter_spec ($@) { my $spec =3D shift; my @packages =3D sort @_; use POSIX qw(strftime); my $date =3D strftime "%a %b %d %Y", localtime; my $fmt =3D <; s/^$catch/$tag/mo=20 or s/^(%package|%description)\b/$tag\n$1/m or die "$progname: $spec: bad specfile\n"; print; } ################################################################ sub usage ($) { use Pod::Usage qw(pod2usage); my $rv =3D shift; pod2usage -message =3D> "$progname: calculate build dependencies", -output =3D> $rv ? \*STDERR : \*STDOUT, -exitval =3D> $rv, -verbose =3D> 1; }=09 use Getopt::Long qw(GetOptions); GetOptions help =3D> \my $opt_help, filereq =3D> \my $opt_filereq,=20 packagereq =3D> \my $opt_packagereq, squeeze =3D> \my $opt_squeeze or usage(1); my $opt_buildreq =3D not ($opt_filereq or $opt_packagereq or $opt_squeeze); die "$progname: options --filereq, --packagereq and --squeeze are mutually = exclusive\n" unless $opt_filereq xor $opt_packagereq xor $opt_squeeze xor $opt_buildreq; usage(0) if $opt_help; usage(1) if not @ARGV; ################################################################ if ($opt_filereq) { local $, =3D local $\ =3D "\n"; print filereq(@ARGV); } elsif ($opt_squeeze) { optimize(@ARGV); } elsif ($opt_packagereq) { my $packages =3D explain(packagereq(@ARGV)); optimize(keys %$packages); } else { foreach my $spec (@ARGV) { my $packages =3D explain(buildreq($spec)); my @packages =3D optimize(keys %$packages); alter_spec($spec, @packages) if @packages; } } __END__ =3Dhead1 NAME buildreq2 - calculate build dependencies =3Dhead1 SYNOPSIS buildreq2 specfile... buildreq2 --filereq cmd [args...] buildreq2 --packagereq cmd [args...] buildreq2 --squeeze pkg... =3Dhead1 AUTHOR Written by Alexey Tourbin , based upon earlier work by Dmitry V. Levin . =3Dhead1 COPYING Copyright (c) 2004, 2005 Alexey Tourbin, ALT Linux Team. This is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. =3Dcut --WTbgq2twYBxfsYA6-- --+nLR7g8KNfrRqv5t Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.5 (GNU/Linux) iD8DBQFCWy7BfBKgtDjnu0YRAuK0AJ9U75L1Co4eXOdJR+74ZiYwfrfS1gCggNfB NCwOJ+WCuw/VLg+0yPFCE9o= =w0Xo -----END PGP SIGNATURE----- --+nLR7g8KNfrRqv5t--