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