Avoid noise from python bytecompile on non-python pkgs (RhBug:539635)
[platform/upstream/rpm.git] / scripts / rpm_fulldb_update
1 #!/usr/bin/perl
2
3 # A perl script to be run from cron which creates an rpm database of
4 # all your binary RPMS.  This database contains the most recent
5 # version of every branch of each package found in the package
6 # repositories.  The database is useful for querying since it is as if
7 # you have installed all these packages into your system.  You can
8 # find which packages hold a file or which packages satify a
9 # dependency.  We are only load the information from the packages and
10 # do not save the contents of the packages into the file system.
11
12 # Branch is a Version Control concept and is coded into the packages
13 # rpm version by convention.  We build the same packages for many
14 # different projects.  Each project works on its own branch and may
15 # have different source code for the same rpm.  The branch name is
16 # encouded in the version number of the package followed by a '.'.
17 # The full database needs to have the most recent copy of each package
18 # on each branch. For example rpm package version "3.43" would be the
19 # "43" release of the branch "3" and rpm package version "potato.91"
20 # would be the "91" release of the "potato" branch.
21
22 # written by Ken Estes kestes@staff.mail.com
23
24
25 use File::Basename;
26 use File::stat;
27
28
29
30 # An rpm_package is a hash of:
31 #     $package{'fqn'}="perl-5.00502-3"
32 #     $package{'rpm_file'}="$RPMS_DIR/".
33 #                "./sparc/perl-5.00502-3.solaris2.6-sparc.rpm"
34 #     $package{'srpm_file'}="$SRPMS_DIR/".
35 #                           "./perl-5.00502-3.src.rpm"
36 #     $package{'name'}="perl"
37 #     $package{'version'}="5.00502"
38 #     $package{'release'}="3"
39
40 # fqn is "fully qualified name"
41
42 # the packages are stored in the datastructure
43 #       $BY_NAME{$name}{$branch}{$version}{$release};
44
45
46
47 sub set_static_vars {
48
49 # This functions sets all the static variables which are often
50 # configuration parameters.  Since it only sets variables to static
51 # quantites it can not fail at run time. Some of these variables are
52 # adjusted by parse_args() but asside from that none of these
53 # variables are ever written to. All global variables are defined here
54 # so we have a list of them and a comment of what they are for.
55
56   $VERSION = ( qw$Revision: 1.2 $ )[1]; 
57
58   @ORIG_ARGV = @ARGV;
59
60   # The pattern for parsing fqn into ($name, $version, $release).
61   # This is difficult to parse since some hyphens are significant and
62   # others are not, some packages have alphabetic characters in the
63   # version number.
64
65   $PACKAGE_PAT ='(.*)-([^-]+)-([^-]+).solaris2.6-\w*.rpm';
66
67   # packages which will end up in the database match this pattern
68   # currently we are not retricting the packages which go into the
69   # database.
70
71   $PICKLIST_PAT = '.';
72
73   # the list of  directories where rpms are stored
74   @RPM_ARCHIVES = ('/export/rpms/redhat',);
75
76   # the full path name of the database we are creating.
77
78   $RPM_DB_DIR = "/export/rpms/redhat/repository.rpmdb";
79
80   # set a known path.
81   
82   # the correct path has not been finalized yet, but this is close.
83   
84   $ENV{'PATH'}= (
85                  '/usr/local/bin'.
86                  ':/usr/bin'.
87                  ':/bin'.
88                  '');
89   
90   # taint perl requires we clean up these bad environmental
91   # variables.
92   
93   delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
94   
95   return 1;
96 } #set_static_vars
97
98
99
100
101 sub get_env {
102
103 # this function sets variables similar to set_static variables.  This
104 # function may fail only if the OS is in a very strange state.  after
105 # we leave this function we should be all set up to give good error
106 # handling, should things fail.
107
108   $| = 1; 
109   $PID = $$; 
110   $PROGRAM = basename($0); 
111   $TIME = time();
112   $LOCALTIME = localtime($main::TIME); 
113   $START_TIME = $TIME;
114
115   {
116     my ($sec,$min,$hour,$mday,$mon,
117         $year,$wday,$yday,$isdst) =
118           localtime(time());
119     
120     # convert confusing perl time vars to what users expect
121     
122     $year += 1900;
123     $mon++;
124     
125     $DATE_STR = sprintf("%02u%02u%02u", $year, $mon, $mday, );
126     $TIME_STR = sprintf("%02u%02u", $hour, $min);
127   }
128   # a unique id for cache file generation
129   $UID = "$DATE_STR.$TIME_STR.$PID";
130
131   return 1;
132 } # get_env
133
134
135
136 sub parse_fqn {
137
138   # This is difficult to parse since some hyphens are significant and
139   # others are not, some packages have alphabetic characters in the
140   # version number. 
141
142   # Also remember that the format of the file is dependent on how RPM
143   # is configured so this may not be portable to all RPM users.
144
145   (!("@_" =~ m/^$PACKAGE_PAT$/)) &&
146     die("rpm_package_name: '@_' is not in a valid format");
147   
148   return ($1, $2, $3);
149 }
150
151
152 sub new_rpm_package {
153
154 # An rpm_package is a hash of:
155 #     $package{'fqn'}="perl-5.00502-3"
156 #     $package{'rpm_file'}="$RPMS_DIR/".
157 #                "./sparc/perl-5.00502-3.solaris2.6-sparc.rpm"
158 #     $package{'srpm_file'}="$SRPMS_DIR/".
159 #                           "./perl-5.00502-3.src.rpm"
160 #     $package{'name'}="perl"
161 #     $package{'version'}="5.00502"
162 #     $package{'release'}="3"
163
164   my ($rpm_file) = @_;
165   my $error = '';  
166   my($name, $version, $release) = main::parse_fqn(basename($rpm_file));
167
168   my ($package) = ();
169   
170   $package->{'fqn'}="$name-$version-$release";
171   $package->{'name'}=$name;
172   $package->{'version'}=$version;
173   $package->{'release'}=$release;
174   $package->{'rpm_file'}=$rpm_file;
175
176   # these are needed to do proper sorting of major/minor numbers in
177   # the version of the package
178
179   $package->{'version_cmp'}=[split(/\./, $version)];
180   $package->{'release_cmp'}=[split(/\./, $release)]; 
181
182   # our packages have a naming convention where then branch name is
183   # the first part of the version.
184
185   $package->{'branch'}= @{ $package->{'version_cmp'} }[0];
186
187   return $package;
188 }
189
190
191 # return the most recent version of package for a given package name/branch pair
192
193 sub get_latest_fqn {
194   my ($name, $branch) =(@_);
195
196   my @out = ();
197
198   foreach $version ( keys %{ $BY_NAME{$name}{$branch} }) {
199     foreach $release ( keys %{ $BY_NAME{$name}{$branch}{$version} }) {
200
201       push @out, $BY_NAME{$name}{$branch}{$version}{$release};
202
203     }
204   }
205
206   # the $BY_NAME datastructure is fairly good but the list can not be
207   # sorted right. Sort again using the Schwartzian Transform as
208   # discribed in perlfaq4
209
210   my @sorted = sort {
211
212     # compare the versions but make no assumptions
213     # about how many elements there are
214     
215     my $i=0;
216     my @a_version = @{ $a->{'version_cmp'} }; 
217     my @b_version = @{ $b->{'version_cmp'} };
218     while ( 
219            ($#a_version > $i) && 
220            ($#b_version > $i) && 
221            ($a_version[$i] == $b_version[$i]) 
222           ) {
223       $i++;
224     }
225     
226     my $j = 0;
227     my @a_release = @{ $a->{'release_cmp'} }; 
228     my @b_release = @{ $b->{'release_cmp'} };
229     while ( 
230            ($#a_release > $j) && 
231            ($#b_release > $j) &&
232            ($a_release[$j] == $b_release[$j])
233           ) {
234       $j++;
235     }
236     
237     return (
238             ($b_version[$i] <=> $a_version[$i])
239             ||
240             ($b_release[$j] <=> $a_release[$j])
241            );
242   }
243   @out;
244
245   return @sorted[0];
246 }
247
248
249 # traverse the package repositories and create a data structure of all
250 # the packages we find.
251
252 sub parse_package_names {
253   my $db_dir = basename($RPM_DB_DIR);
254   foreach $archive (@RPM_ARCHIVES) {
255     
256     open(FILES, "-|") || 
257       exec("find", $archive, "-print") ||
258         die("Could not run find. $!\n");
259
260     while ($filename = <FILES>) { 
261
262       # we want only the binary rpm files of interest
263
264       ($filename =~ m/\.rpm$/) || next;
265       ($filename =~ m/\.src\.rpm$/) && next;
266       ($filename =~ m/$PICKLIST_PAT/) || next;
267
268       # do not mistake database files for packages
269
270       ($filename =~ m!/$db_dir/!) && next;
271
272       chomp $filename;
273
274       $pkg = new_rpm_package($filename);
275       $BY_NAME{$pkg->{'name'}}{$pkg->{'branch'}}{$pkg->{'version'}}{$pkg->{'release'}} = $pkg;
276
277     }
278
279     close(FILES) || 
280       die("Could not close find. $!\n");
281     
282   }
283
284   return %BY_NAME;
285 }
286
287
288
289 # traverse the data structure of all the packages and load the most
290 # recent version from each branch into the database.  We are only
291 # loading the information from the package not saving the files into
292 # the file system.
293
294 sub create_new_db {
295
296
297   my $uid = $<;
298   
299   # eventually there will be a builder id who will run this code but
300   # for now.
301   
302   ($uid == 0 ) && 
303     die("Must not run this program as root\n");
304   
305   # set up to load the database
306
307   {
308
309     my $tmp_db = "$RPM_DB_DIR.$UID";
310     
311     system("mkdir", "-p", $tmp_db, );
312     ($?) && 
313       die("$0: System error: $! \n");
314     
315     system("rpm", "--initdb",
316            "--dbpath", $tmp_db, );
317     ($?) && 
318       die("$0: System error: $! \n");
319     
320     open(README, ">$tmp_db/README") ||
321       die("Could not open $tmp_db/README. $! \n");
322     print README <<EOF;
323 #
324 # This directory is updated daily by a cron job. 
325 # program: $0
326 # version: $VERSION
327 # updated ran at: $LOCALTIME
328
329 # This directory contains an rpm database which has been loaded with
330 # the most recent version of every package in our archive.  It is
331 # intended to be used for queries to find packages. Example:
332
333 # rpm --dbpath /net/master-mm/export/rpms/redhat/rpmfulldb 
334 #       -q --whatprovides 'java(com.iname.site.context.LoginContext)'
335
336
337 # rpm --dbpath /net/master-mm/export/rpms/redhat/rpmfulldb 
338 #       -qf /usr/local/bin/rpmdiff
339
340
341 EOF
342     close(README) ||
343       die("Could not close $tmp_db/README. $! \n");
344   }
345
346   # load the database with the packages we want.
347
348   foreach $pkg_name (keys %BY_NAME) {
349     foreach $branch (keys %{ $BY_NAME{$pkg_name} }) {
350       $pkg_file = get_latest_fqn($pkg_name, $branch)->{'rpm_file'};
351
352       system("rpm", "-i", "--nodeps", "--noscripts", "--justdb", 
353              "--dbpath", $tmp_db, 
354              $pkg_file);
355       ($?) && 
356         die("$0: System error: $! \n");
357     }
358   }
359
360   # do the update as close to atomically as is practicale.
361
362   system("rm", "-rf", $RPM_DB_DIR,);
363   ($?) && 
364     die("$0: System error: $! \n");
365   
366   rename($tmp_db, $RPM_DB_DIR,) || 
367     die("Could not rename file: $tmp_db => $RPM_DB_DIR. $! \n");
368
369   return ;
370 }
371
372
373
374
375
376 #       Main        
377 {
378   set_static_vars();
379   get_env();
380
381   my %by_name=parse_package_names();
382   create_new_db(%by_name);
383
384   exit 0;
385 }
386