Fix building issue for tizen_base(configure: error: --with-msm given, but attr/xattr...
[platform/upstream/rpm.git] / scripts / osgideps.pl
1 #!/usr/bin/perl
2 #
3 # osgideps.pl -- Analyze dependencies of OSGi bundles.
4 #
5 # Kyu Lee (initial idea)
6 # Alphonse Van Assche <alcapcom@fedoraproject.org> (current maintainer)
7 #
8 # $Id: osgideps.pl,v 1.0 2009/06/08 12:12:12 mej Exp $
9
10 use Getopt::Long;
11 use File::Temp qw/ tempdir /;
12 use threads;
13 use Thread::Queue;
14
15 $MANIFEST_NAME = "META-INF/MANIFEST.MF";
16
17 # parse options
18 my ( $show_provides, $show_requires, $show_system_bundles, $debug );
19 my $result = GetOptions(
20         "provides" => \$show_provides,
21         "requires" => \$show_requires,
22         "system" => \$show_system_bundles,
23         "debug" => \$debug
24 );
25 exit(1) if ( not $result );
26
27 # run selected function
28 @allfiles = <STDIN>;
29 if ($show_provides) {
30         getProvides(@allfiles);
31 }
32 if ($show_requires) {
33         getRequires(@allfiles);
34 }
35 if ($show_system_bundles) {
36         getSystemBundles(@allfiles);
37 }
38 exit(0);
39
40 # this function print provides of OSGi aware files
41 sub getProvides {
42         
43         my $queue = Thread::Queue->new;
44         foreach $file (@_) {
45                 $queue->enqueue($file);
46         }
47
48         my @workers;
49         push @workers, threads->create('getProvidesWorker');
50         push @workers, threads->create('getProvidesWorker');
51         push @workers, threads->create('getProvidesWorker');
52         push @workers, threads->create('getProvidesWorker');
53
54         map { $_->join } @workers;
55         
56         sub getProvidesWorker {
57                 while ( my $file = $queue->dequeue_nb ) {
58                         chomp($file);
59                         # we don't follow symlinks for provides
60                         next if ( -f $file && -r _ && -l _ );
61                         $file =~ s/[^[:print:]]//g;
62                         if ( $file =~ m/$MANIFEST_NAME$/ || $file =~ m/\.jar$/ ) {
63                                 if ( $file =~ m/\.jar$/ ) {
64                                         if ( `zipinfo -1 $file 2> /dev/null | grep -e \^$MANIFEST_NAME` eq "$MANIFEST_NAME\n" ) {
65                                                 # extract MANIFEST.MF file from jar to temporary directory
66                                                 $tmpdir = tempdir( CLEANUP => 1 );                                              
67                                                 `unzip -d $tmpdir -qqo $file $MANIFEST_NAME`;
68                                                 open( MANIFEST, "$tmpdir/$MANIFEST_NAME" );
69                                         }
70                                 } else {
71                                         open( MANIFEST, "$file" );
72                                 }
73                                 my $bundleName = "";
74                                 my $version = "";
75                                 # parse Bundle-SymbolicName, Bundle-Version and Export-Package attributes
76                                 while (<MANIFEST>) {
77                                         # get rid of non-print chars (some manifest files contain weird chars)
78                                         s/[^[:print]]//g;
79                                         if ( m/(^(Bundle-SymbolicName): )(.*)$/ ) {
80                                                 $bundleName = "$3" . "\n";
81                                                 while (<MANIFEST>) {
82                                                         if ( m/^[[:upper:]][[:alpha:]]+-[[:upper:]][[:alpha:]]+: .*/ ) {
83                                                                 $len = length $_;
84                                                                 seek MANIFEST, $len * -1, 1;
85                                                                 last;
86                                                         }
87                                                         $bundleName .= "$_";
88                                                 }
89                                                 $bundleName =~ s/\s+//g;
90                                                 $bundleName =~ s/;.*//g;
91                                         }
92                                         if ( m/(^Bundle-Version: )(.*)/ ) {
93                                                 $version = $2;
94                                         }
95                                         if ( m/(^(Export-Package): )(.*)$/ ) {
96                                                 my $bunlist = "$3" . "\n";
97                                                 while (<MANIFEST>) {
98                                                         if ( m/^[[:upper:]][[:alpha:]]+-[[:upper:]][[:alpha:]]+: .*/ ) {
99                                                                 $len = length $_;
100                                                                 seek MANIFEST, $len * -1, 1;
101                                                                 last;
102                                                         }
103                                                         $bunlist .= "$_";
104                                                 }
105                                                 push @bundlelist, parsePkgString($bunlist, $file);
106                                         }
107                                 }       
108         
109                                 # skip this jar if no bundle name exists
110                                 if ( !$bundleName eq "" ) {
111                                         if ( !$version eq "" ) {
112                                                 $version = parseVersion($version);
113                                                 push @bundlelist, { FILE => "$file", NAME => "$bundleName", VERSION => "$version" };
114                                         } else {        
115                                                 push @bundlelist, { FILE => "$file", NAME => "$bundleName", VERSION => "" };
116                                         }
117                                 }
118                                 `rm -rf $tmpdir`;
119                         }
120                 }
121                 if ( !$debug ) { @bundlelist = prepareOSGiBundlesList(@bundlelist); }
122                 $list = "";
123                 for $bundle (@bundlelist) {
124                         if ( !$debug ) {
125                                 $list .= "osgi(" . $bundle->{NAME} . ")" . $bundle->{VERSION} . "\n";
126                         } else {
127                                 $list .= $bundle->{FILE} . " osgi(" . $bundle->{NAME} . ")" . $bundle->{VERSION} . "\n";
128                         }
129                 }
130                 print $list;
131         }
132 }
133
134 # this function print requires of OSGi aware files
135 sub getRequires {
136
137         my $queue = Thread::Queue->new;
138         foreach $file (@_) {
139                 $queue->enqueue($file);
140         }
141
142         my @workers;
143         push @workers, threads->create('getRequiresWorker');
144         push @workers, threads->create('getRequiresWorker');
145         push @workers, threads->create('getRequiresWorker');
146         push @workers, threads->create('getRequiresWorker');
147
148         map { $_->join } @workers;
149         
150         sub getRequiresWorker {
151                 while ( my $file = $queue->dequeue_nb ) {
152                         next if ( -f $file && -r _ );
153                         $file =~ s/[^[:print:]]//g;
154                         if ( $file =~ m/$MANIFEST_NAME$/ || $file =~ m/\.jar$/ ) {
155                                 # we explicitly requires symlinked jars
156                                 # _that_reside_outside_the_package_
157                                 if (-l $file) {
158                                         $exist = 0;
159                                         $lnksrc = `readlink -qen $file`;
160                                         foreach $exfile ( @allfiles ) {
161                                                 $exfile =~ s/[^[:print:]]//g;
162                                                 if ( $lnksrc =~ m/$exfile$/ ) {                                                 
163                                                         $exist = 1;
164                                                         last;
165                                                 }
166                                         }
167                                         print "$lnksrc\n" if (!$exist);
168                                         next;
169                                 }        
170                                 
171                                 if ( $file =~ m/\.jar$/ ) {
172                                         if ( `zipinfo -1 $file 2> /dev/null | grep -e \^$MANIFEST_NAME` eq "$MANIFEST_NAME\n" ) {
173                                                 # extract MANIFEST.MF file from jar to temporary directory
174                                                 $tmpdir = tempdir( CLEANUP => 1 );
175                                                 `unzip -d $tmpdir -qqo $file $MANIFEST_NAME`;
176                                                 open( MANIFEST, "$tmpdir/$MANIFEST_NAME" );
177                                         }
178                                 } else {
179                                         open( MANIFEST, "$file" );
180                                 }
181                                 while (<MANIFEST>) {
182                                         if ( m/(^(Require-Bundle|Import-Package): )(.*)$/ ) {
183                                                 my $bunlist = "$3" . "\n";
184                                                 while (<MANIFEST>) {
185                                                         if (m/^[[:upper:]][[:alpha:]]+-[[:upper:]][[:alpha:]]+: .*/ ) {
186                                                                 $len = length $_;
187                                                                 seek MANIFEST, $len * -1, 1;
188                                                                 last;
189                                                         }
190                                                         $bunlist .= "$_";
191                                                 }
192                                                 push @bundlelist, parsePkgString($bunlist, $file);
193                                         }
194                                         # we also explicitly require symlinked jars define by 
195                                         # Bundle-ClassPath attribut
196                                         if ( m/(^(Bundle-ClassPath): )(.*)$/ ) {
197                                                 $bunclp = "$3" . "\n";
198                                                 while (<MANIFEST>) {
199                                                         if ( m/^[[:upper:]][[:alpha:]]+-[[:upper:]][[:alpha:]]+: .*/ ) {
200                                                                 $len = length $_;
201                                                                 seek MANIFEST, $len * -1, 1;
202                                                                 last;
203                                                         }
204                                                         $bunclp .= "$_";
205                                                 }
206                                                 $bunclp =~ s/\ //g;
207                                                 $bunclp =~ s/\n//g;
208                                                 $bunclp =~ s/[^[:print:]]//g;
209                                                 $dir = `dirname $file`;
210                                                 $dir =~ s/\n//g;
211                                                 @jars = split /,/, $bunclp;
212                                                 for $jarfile (@jars) {
213                                                         $jarfile = "$dir\/\.\.\/$jarfile";
214                                                         $jarfile = readlink $jarfile;
215                                                         if ( !$jarfile eq "" ) {                                                        
216                                                                 print "$jarfile" . "\n";
217                                                         }
218                                                 }
219                                         }
220                                 }
221                                 `rm -rf $tmpdir`;
222                         }
223                 }
224                 if ( !$debug ) { @bundlelist = prepareOSGiBundlesList(@bundlelist); }
225                 $list = "";
226                 for $bundle (@bundlelist) {
227                         # replace '=' by '>=' because qualifiers are set on provides 
228                         # but not on requires.
229                         $bundle->{VERSION} =~ s/\ =/\ >=/g;
230                         if ( !$debug ) {
231                                 $list .= "osgi(" . $bundle->{NAME} . ")" . $bundle->{VERSION} . "\n";
232                         } else {
233                                 $list .= $bundle->{FILE} . " osgi(" . $bundle->{NAME} . ")" . $bundle->{VERSION} . "\n";
234                         }
235                 }
236                 print $list;
237         }
238 }
239
240 # this function print system bundles of OSGi profile files.
241 sub getSystemBundles {
242         foreach $file (@_) {
243                 if ( ! -f $file || ! -r _ ) {
244                         print "'$file' file not found or cannot be read!";
245                         next;
246                 } else {
247                         open( PROFILE, "$file" );
248                         while (<PROFILE>) {
249                                 if ( $file =~ m/\.profile$/ ) {
250                                         if (m/(^(org\.osgi\.framework\.system\.packages)[=|\ ]+)(.*)$/) {
251                                                 $syspkgs = "$3" . "\n";
252                                                 while (<PROFILE>) {
253                                                         if (m/^[a-z]/) {
254                                                                 $len = length $_;
255                                                                 seek MANIFEST, $len * -1, 1;
256                                                                 last;
257                                                         }
258                                                         $syspkgs .= "$_";
259                                                 }
260                                                 $syspkgs =~ s/\s+//g;
261                                                 $syspkgs =~ s/\\//g;
262                                                 @bundles = split /,/, $syspkgs;
263                                                 foreach $bundle (@bundles) {
264                                                         print "osgi(" . $bundle . ")\n";
265                                                 }
266                                         }
267                                 }
268                         }
269                 }
270         }
271 }
272
273 sub parsePkgString {
274         my $bunstr = $_[0];
275         my $file = $_[1];
276         my @return;
277         $bunstr =~ s/ //g;
278         $bunstr =~ s/\n//g;
279         $bunstr =~ s/[^[:print:]]//g;
280         $bunstr =~ s/("[[:alnum:]|\-|\_|\.|\(|\)|\[|\]]+)(,)([[:alnum:]|\-|\_|\.|\(|\)|\[|\]]+")/$1 $3/g;
281         # remove uses bundle from Export-Package attribute
282         $bunstr =~ s/uses:="[[:alnum:]|\-|\_|\.|\(|\)|\[|\]|,]+"//g;
283         # remove optional dependencies
284         $bunstr =~ s/,.*;resolution:=optional//g;
285         # remove x-friends
286         $bunstr =~ s/;x-friends:="[[:alnum:]|\-|\_|\.|\(|\)|\[|\]|,]+"//g;
287         # remove signatures 
288         $bunstr =~ s/Name:.*SHA1-Digest:.*//g;
289         @reqcomp = split /,/, $bunstr;
290         foreach $reqelement (@reqcomp) {
291                 @reqelementfrmnt = split /;/, $reqelement;
292                 $name = "";
293                 $version = "";
294                 $name = $reqelementfrmnt[0];
295                 $name =~ s/\"//g;
296                 # ignoring OSGi 'system.bundle' 
297                 next if ( $name =~ m/^system\.bundle$/ );
298                 for $i ( 1 .. $#reqelementfrmnt ) {
299                         if ( $reqelementfrmnt[$i] =~ m/(^(bundle-|)version=")(.*)(")/ ) {
300                                 $version = $3;
301                                 last;
302                         }
303                 }
304                 $version = parseVersion($version);
305                 push @return, { FILE => "$file", NAME => "$name", VERSION => "$version" };
306         }
307         return @return;
308 }
309
310 sub parseVersion {
311         my $ver = $_[0];
312         if ( $ver eq "" ) { return ""; }
313         if ( $ver =~ m/(^[\[|\(])(.+)\ (.+)([\]|\)]$)/ ) {
314                 if ( $1 eq "\[" ) {
315                         $ver = " >= $2";
316                 } else {
317                         $ver = " > $2";
318                 }
319         } else {
320                 $ver = " = $ver";
321         }
322         # we always return a full OSGi version to be able to match 1.0
323         # and 1.0.0 as equal in RPM.
324         ( $major, $minor, $micro, $qualifier ) = split( '\.', $ver );
325         if ( !defined($minor) || !$minor ) {
326                 $minor = 0;
327         }
328         if ( !defined($micro) || !$micro ) {
329                 $micro = 0;
330         }
331         if ( !defined($qualifier) || !$qualifier ) {
332                 $qualifier = "";
333         } else {
334                 $qualifier = "." . $qualifier;
335         }
336         $ver = $major . "." . $minor . "." . $micro . $qualifier;
337         return $ver;
338 }
339
340 # this function put the max version on each bundles to be able to remove
341 # duplicate deps with 'sort -u' command.
342 sub prepareOSGiBundlesList {
343         foreach $bundle (@_) {
344                 foreach $cmp (@_) {
345                         if ( $bundle->{NAME} eq $cmp->{NAME} ) {
346                                 $result = compareVersion( $bundle->{VERSION}, $cmp->{VERSION} );
347                                 if ( $result < 0 ) {
348                                         $bundle->{VERSION} = $cmp->{VERSION};
349                                 }
350                         }
351                 }
352         }
353         return @_; 
354 }
355
356 # this function returns a negative integer, zero, or a positive integer if 
357 # $ver1 is less than, equal to, or greater than $ver2.
358 #
359 # REMEMBER: we mimic org.osgi.framework.Version#compareTo method but
360 # *at this time* we don't take care of the qualifier part of the version.
361 sub compareVersion {
362         my $ver1 = $_[0];
363         my $ver2 = $_[1];
364         
365         $ver1 = "0.0.0" if ( $ver1 eq "" );
366         $ver2 = "0.0.0" if ( $ver2 eq "" );
367
368         $ver1 =~ m/([0-9]+)(\.)([0-9]+)(\.)([0-9]+)/;
369         $major1 = $1;
370         $minor1 = $3;
371         $micro1 = $5;
372
373         $ver2 =~ m/([0-9]+)(\.)([0-9]+)(\.)([0-9]+)/;
374         $major2 = $1;
375         $minor2 = $3;
376         $micro2 = $5;
377
378         $result = $major1 - $major2;
379         return $result if ( $result != 0 );
380         
381         $result = $minor1 - $minor2;
382         return $result if ( $result != 0 );
383         
384         $result = $micro1 - $micro2;
385         return $result if ( $result != 0 );
386         
387         return $result;
388 }