]> git.pld-linux.org Git - projects/cleanbuild.git/blob - findbr
268907d81419f2d19f61321707b898ac623e9329
[projects/cleanbuild.git] / findbr
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use IPC::Open2;
6
7 # how to run poldek
8 my @ignore = qw(vserver-packages python-devel-src);
9 my @poldek = (qw(sudo poldek -n th -n th-ready --cachedir=./poldekcache --skip-installed),
10         qw(-O keep_downloads=yes -O suggests=no -O unique_package_names=yes),
11         "-O", "ignore=" . (join " ", @ignore)
12 );
13
14 # if multiple packages provide some funcionality those will be selected:
15 my %preferred = (
16         "automake" => +1,
17         "autoconf" => +1,
18         "pkgconfig" => +1,
19
20         "python" => +1,
21         "python-modules" => +1,
22
23         "perl-modules" => +1,
24         "perl-Encode" => +2,
25
26         "zlib-devel" => +1,
27         "libstdc++-devel" => +1,
28 );
29
30 # translate package name to privodes name
31 my %translate = (
32         "rarian-compat" => "scrollkeeper",
33         "Mesa-libGLU-devel" => "OpenGL-GLU-devel",
34 );
35
36 # for m4 in *.m4; do R=$(rpm -qf $m4); R=${R%-*-*}; \
37 #   awk -vr=$R '/^\s*(AC_DEFUN|AU_ALIAS)/ { gsub(/\].*/,""); gsub(/.*\[/,""); print r " " $0}' $m4; \
38 # done | sort | awk '{print "\t\"" $2 "\" => \"" $1 "\","}'
39 my %ac2br = do "findbr-ac2br";
40
41 my %cmake2br = (
42         "findkde4:44" => "kde4-kdelibs",
43         "findmsgfmt" => "gettext-devel",
44         "findpythoninterp" => "python",
45 );
46
47 BEGIN {
48         $SIG{__WARN__} = sub
49         {
50                 local $_ = shift;
51                 chomp;
52                 print STDERR "\033[31;1m" . $_ . "\033[0m\n"
53         };
54 }
55
56 my $builddir = shift @ARGV;
57 my @lines = <ARGV>;
58
59 my $reason;
60
61 my %out;
62 sub add_br
63 {
64         my $pkg = shift;
65         my $msg = shift || $reason;
66         if ( ref $pkg ) {
67                 foreach my $p ( @$pkg ) {
68                         add_br( $p, $msg );
69                 }
70                 return;
71         }
72
73         $msg =~ s/\n/ # /sg;
74
75         $pkg = $translate{ $pkg } || $pkg;
76
77         return if exists $out{ $pkg };
78         $out{ $pkg } = $msg;
79         print STDERR "\033[33;1madding: $pkg => $msg\033[0m\n";
80 }
81
82 sub poldek_cmd
83 {
84         my $cmd = shift;
85         warn "Poldek: $cmd\n";
86         my $pid = open( READ, "-|", @poldek, "--shcmd=".$cmd );
87
88         my @read = <READ>;
89         close READ;
90
91         return @read if wantarray;
92         return \@read;
93 }
94
95 my $check_ac = 0;
96
97 my %checked_files;
98 sub poldek_file
99 {
100         my @files;
101         foreach ( @_ ) {
102                 next if $checked_files{ $_ };
103                 $checked_files{ $_ } = 1;
104                 push @files, $_;
105         }
106         return unless @files;
107
108         my $search = join "; ", map "search -f $_", @files;
109         warn "Reason: $reason\n";
110         my @read = poldek_cmd( $search );
111
112         local $_;
113         my @found;
114         while ( $_ = shift @read ) {
115                 if ( /(\d+) package\(s\) found:$/ ) {
116                         foreach my $i ( 1..$1 ) {
117                                 $_ = shift @read;
118                                 chomp;
119                                 $_ =~ /^(.*)-.*?-.*?$/;
120                                 push @found, $1;
121                         }
122                 }
123         }
124
125         return unless @found;
126
127         my $found = $found[0];
128         if ( @found > 1 ) {
129                 my $i = 0.0;
130                 my %pts = map { ( $_ => ( ($i += 0.001) + ( $preferred{ $_ } || 0 ) ) ) }
131                         reverse @found;
132                 my @pref = sort { $pts{$b} <=> $pts{$a} } @found;
133                 my $pref = join ", ", map "$_ => $pts{$_}", @pref;
134                 warn "Multiple found: $pref\n";
135                 $found = $pref[0];
136         }
137
138         $found = $translate{ $found } if $translate{ $found };
139
140         add_br( $found );
141 }
142
143 my $pkglist;
144 sub get_pkglist
145 {
146         my %pkglist;
147         my $read = poldek_cmd( "ls" );
148         foreach ( @$read ) {
149                 chomp;
150                 next unless /(\S+)-.*?-.*?\.[a-z0-9_]+$/;
151                 my $pkg = $1;
152                 $pkglist{ lc $pkg } = $pkg;
153         }
154         $pkglist = \%pkglist;
155 }
156
157 sub guess_package
158 {
159         my $origname = shift;
160         get_pkglist() unless $pkglist;
161         return unless defined $origname;
162         my $name = lc $origname;
163         my @try = (
164                 "lib$name-devel",
165                 "$name-devel",
166                 "$name",
167                 "lib$name-.*-devel",
168                 "$name-.*-devel",
169                 ".*-lib$name-devel",
170                 ".*-$name-devel",
171                 ".*-lib$name-.*-devel",
172                 ".*-$name-.*-devel",
173         );
174         my @select;
175         for my $k ( keys %$pkglist ) {
176                 if ( $k =~ /$name/ ) {
177                         push @select, $k;
178                 }
179         }
180         @select = sort @select;
181
182         foreach my $try ( @try ) {
183                 foreach my $pkg ( @select ) {
184                         if ( $pkg =~ /^$try$/ ) {
185                                 warn "guessed: $origname => $pkglist->{ $pkg }\n";
186                                 return $pkglist->{ $pkg };
187                         }
188                 }
189         }
190         warn "$origname not guessed\n";
191         return undef;
192 }
193
194 my %checked;
195 my $cmake_get_call = 0;
196 my $cmake_pkg_list = 0;
197 while ( $_ = shift @lines ) {
198         chomp;
199         #next if $checked{ $_ };
200         #$checked{ $_ } = 1;
201
202         $reason = $_;
203         if ( /^\S+: (\S+): (?:Command )?not found$/ or /.*configure\[\d+\]: (\S+): not found$/
204                         or m{which: no (\S+) in \(.*/bin.*\)}
205                         or m{\S+: (\S+): command not found$}
206                         or m{Can't exec "(\S+)": No such file or directory} ) {
207                 my $exec = $1;
208                 next if $exec eq "hostname";
209                 warn "Looking for executable $exec\n";
210                 if ( $exec =~ m#^/# ) {
211                         poldek_file( $exec );
212                 }
213                 poldek_file( "/usr/bin/$exec", "/bin/$exec" );
214         }
215                         
216
217         if ( /\S+\.[ch](?:pp|xx)?:\d+:\d+: error: (\S+): No such file or directory$/ ) {
218                 my $h = $1;
219                 warn "Looking for C(++) header $h\n";
220                 poldek_file( "/usr/include*/$h" );
221         }
222         if ( m{^ImportError: No module named (\S+)$} ) {
223                 my $mod = $1;
224                 $mod =~ s#\.#/#g;
225                 warn "Looking for python module $mod\n";
226                 poldek_file( "/usr/share/python2*/$mod/__init__.py*",
227                                 "/usr/share/python2*/$mod.py*",
228                                 "/usr/lib*/python2*/$mod.py*",
229                                 "/usr/lib*/python2*/_$mod.so" );
230         }
231         if ( /configure(?:\.in|\.ac)?:\d+: error: possibly undefined macro: (\S+)/ 
232                         or m{configure(?:\.in|\.ac)?:\d+: error: m4 macro `(\S+)' is not defined} ) {
233                 my $macro = $1;
234                 warn "Looking for autotools macro $macro\n";
235                 if ( my $br = $ac2br{ $macro } ) {
236                         add_br( $br );
237                         next;
238                 }
239         }
240         if ( /^No package '(\S+)' found$/ or
241                         /Package (\S+) was not found in the pkg-config search path/
242                                 or m{None of the required '(\S+?)(?:[<>=].*)?' found}
243                                 or m{--\s+package '(\S+?)(?:[<>=].*)?' not found}
244                 ) {
245                 my $pkg = $1;
246                 warn "Looking for package $pkg\n";
247                 poldek_file( "/usr/lib*/pkgconfig/$pkg.pc" );
248         }
249         if ( m{^cp: cannot stat `(/.*)': No such file or directory$} ) {
250                 my $f = $1;
251                 warn "Looking for file $f\n";
252                 poldek_file( $f );
253         }
254         if ( m{^find-lang.sh: Error: international files not found for '}
255                         or m{ gettext tools not found}
256                         ) {
257                 add_br( "gettext-devel" );
258                 #exit;
259                 next;
260         }
261         if ( m{ pkg-config .*not .*found}
262                         or m{^checking for pkg-config\.\.\. no} ) {
263                 add_br( "pkgconfig" );
264                 #exit;
265                 next;
266         }
267         if ( m{^Can't locate (.*?\.pm) in \@INC} ) {
268                 my $mod = $1;
269                 warn "Looking for perl module $mod\n";
270                 poldek_file( "/usr/lib*/perl*/$mod", "/usr/share/perl*/$mod" );
271         }
272         if ( m{^/usr/bin/ld: cannot find -l(.*?)$} ) {
273                 my $lib = $1;
274                 warn "Looking for library $lib\n";
275                 poldek_file( "/usr/lib*/lib$lib.so" );
276         }
277         if ( m{^error: Couldn't exec (/\S+): No such file or directory$} 
278                         or m{^Can't open perl script "(/\S+)": No such file or directory$}
279                         or m{unable to open (/\S+) \(No such file or directory\)$}
280                         or m{GConf-CRITICAL \*\*: No such file `(/.\S+?)'$}
281                         or m{make.*: \*\*\* No rule to make target `(/\S+)'}
282                         or m{g(?:cc|\+\+): (/\S+): No such file or directory$}
283                         ) {
284                 my $file = $1;
285                 warn "Looking for file $file\n";
286                 poldek_file( $file );
287         }
288         if ( m{failed.*http://www\.oasis-open\.org/docbook/xml/([\d\.]+/\S+\.dtd)} ) {
289                 my $dtd = $1;
290                 warn "Looking for docbook file $dtd\n";
291                 poldek_file( "/usr/share/sgml/docbook/xml-dtd-$dtd" );
292         }
293         if ( m{http://docbook.sourceforge.net/release/xsl/current/(\S+\.xsl)} ) {
294                 my $db = $1;
295                 next if m{^\s*(/usr/bin/)?xsltproc };
296                 warn "Looking for docbook file $db\n";
297                 poldek_file( "/usr/share/sgml/*/$db" );
298         }
299         if ( m{configure: error: C\+\+ preprocessor "/lib/cpp" fails sanity check} ) {
300                 add_br( "gcc-c++", "try: %undefine\t__cxx" );
301         }
302         if ( m{configure: error: C\+\+ compiler cannot create executables} ) {
303                 add_br( "libstdc++-devel", "maybe try: %undefine\t__cxx" );
304         }
305         if ( m{configure: error: XML::Parser perl module is required for intltool} ) {
306                 add_br( "perl-XML-Parser" );
307         }
308
309         if ( m{configure\[\d+\]: syntax error: }
310                         or m{\./configure\[\d+\]: \S+_\S+: not found} ) {
311                 warn "Need to check configure source: $reason\n";
312                 $check_ac = 1;
313         }
314
315         if ( m{^CMake Error at (?:\S+/)?(\S+?)\.cmake:(\d+) } ) {
316                 my ( $module, $line ) = ( lc $1, $2 );
317                 my $br;
318                 if ( $module eq "findqt4" ) {
319                         my $l = $lines[0];
320                         chomp $l;
321                         if ( $l =~ /qmake/ ) {
322                                 add_br( "qt4-qmake", $l );
323                         } elsif ( $l =~ /rcc/ ) {
324                                 add_br( "qt4-build", $l );
325                         } elsif ( $l =~ /Could NOT find (Qt\S+) header/ ) {
326                                 add_br( "$1-devel", $l );
327                         } else {
328                                 warn "unrecognized Qt requirement: $l\n";
329                         }
330                 } elsif ( $module eq "cmakedeterminecxxcompiler" ) {
331                         add_br( "libstdc++-devel",
332                                 '"try: -DCMAKE_CXX_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER="%{__cc}"' );
333                 } elsif ( $br = $cmake2br{ $module . ":" . $line } ) {
334                         add_br( $br );
335                 } elsif ( $br = $cmake2br{ $module } ) {
336                         add_br( $br );
337                 } elsif ( $br = guess_package( $module =~ /find(.+)/ ) ) {
338                         add_br( $br );
339                 } else {
340                         $cmake_get_call = 1;
341                         warn "Unrecognized cmake error: $reason\n";
342                 }
343         }
344         if ( m{^\s*ERROR: (?:\S+/)?(\S+?\.cmake) not found} ) {
345                 my $cmake = $1;
346                 warn "Looking for cmake file: $cmake\n";
347                 poldek_file( "/usr/*/cmake/*/$cmake" )
348         }
349         if ( $cmake_get_call ) {
350                 if ( m{^\s*/\S+/(\S+)\.cmake:(\d+) } ) {
351                         my ( $module, $line ) = ( lc $1, $2 );
352                         my $br;
353                         if ( $br = $cmake2br{ $module . ":" . $line } ) {
354                                 add_br( $br );
355                                 $cmake_get_call = 0;
356                         } elsif ( $br = $cmake2br{ $module } ) {
357                                 add_br( $br );
358                                 $cmake_get_call = 0;
359                         } elsif ( $br = guess_package( $module =~ /find(.+)/ ) ) {
360                                 add_br( $br );
361                                 $cmake_get_call = 0;
362                         }
363                 }
364         }
365         if ( m{^-- WARNING: you are using the obsolete 'PKGCONFIG' macro} ) {
366                 add_br( "pkgconfig" );
367         }
368         if ( m{QT_(QT\S+)_LIBRARY \(ADVANCED\)} 
369                         or m{X11_(\S+)_LIB \(ADVANCED\)}
370                         or m{Qt (\S+) library not found} ) {
371                 my $find = $1;
372                 my $pkg = guess_package( $find );
373                 if ( $pkg ) {
374                         add_br( $pkg );
375                 } else {
376                         warn "Cannot quess qt package: $find\n";
377                 }
378         }
379
380         if ( m{^-- The following OPTIONAL packages could NOT be located on your system} ) {
381                 $cmake_pkg_list = 1;
382         }
383         if ( $cmake_pkg_list ) {
384                 if ( /\s+\* (\S+) / ) {
385                         my $find = $1;
386                         my $pkg = guess_package( $find );
387                         if ( $pkg ) {
388                                 add_br( $pkg );
389                         } else {
390                                 warn "Cannot quess optional package: $find\n";
391                         }
392                 } elsif ( /^\s*$/ ) {
393                         $cmake_pkg_list = 0;
394                 }
395         }
396 }
397
398
399
400 sub wanted
401 {
402         return unless /^configure(\.(?:ac|in|in\.in))?$/;
403         return unless -r;
404
405         warn "$File::Find::name\n";
406         open F_IN, "<", $_;
407         my $file = $_;
408         while ( <F_IN> ) {
409                 chomp;
410                 if ( m{^\s*([A-Za-z0-9_]+)\s*(\(.*)?$} ) {
411                         my $def = $1;
412                         if ( my $br = $ac2br{ $def } ) {
413                                 add_br( $br, "$file: $_" );
414                         } elsif ( $def !~ /^A[CM]_/ and $def =~ /^_?[A-Z]+_[A-Z_0-9a-z]+$/ ) {
415                                 #warn "Possible macro unrecognized: $def [[[$_]]]\n";
416                         }
417                 }
418         }
419         close F_IN;
420 }
421
422 use File::Find;
423 if ( $check_ac ) {
424         find( \&wanted, $builddir );
425 }
426
427 foreach my $pkg ( sort keys %out ) {
428         print "$pkg -- $out{$pkg}\n";
429 }
430 # vim: ts=4 sw=4
This page took 0.047759 seconds and 3 git commands to generate.