source: ProjectBuilder/devel/pb/bin/pb.pl@ 27

Last change on this file since 27 was 27, checked in by Bruno Cornec, 17 years ago

Addition of PBPKG use in spec file
rename variable pkg in pbpkg for coherency

  • Property svn:executable set to *
File size: 14.6 KB
Line 
1#!/usr/bin/perl -w
2#
3# Project Builder main application
4#
5# $Id$
6#
7# Copyright B. Cornec 2007
8# Provided under the GPL v2
9
10# Syntax: see at end
11
12use strict 'vars';
13use Getopt::Std;
14use Data::Dumper;
15use English;
16use AppConfig qw(:argcount :expand);
17use File::Basename;
18use File::Copy;
19use Time::localtime qw(localtime);
20use POSIX qw(strftime);
21
22use vars qw (%defpkgdir %extpkgdir %version %confparam %filteredfiles $debug $LOG);
23%extpkgdir = ();
24%filteredfiles = ();
25$debug = 0; # Debug level
26$LOG = *STDOUT; # Where to log
27use lib qw (lib);
28use common qw (env_init);
29use pb qw (pb_init);
30use distro qw (distro_init);
31use cms;
32use changelog qw (changelog);
33
34my %opts; # CLI Options
35my $action; # action to realize
36my $test = "FALSE";
37my $option = "";
38my @pkgs;
39my $pbtag; # Global TAG variable
40my $pbver; # Global VERSION variable
41my $pbrev; # GLOBAL REVISION variable
42my @date=(localtime->sec(), localtime->min(), localtime->hour(), localtime->mday(), localtime->mon(), localtime->year(), localtime->wday(), localtime->yday(), localtime->isdst());
43my $pbdate = strftime("%Y-%m-%d", @date);
44
45getopts('hl:p:qtv',\%opts);
46
47if (defined $opts{'h'}) {
48 syntax();
49 exit(0);
50}
51if (defined $opts{'v'}) {
52 $debug++;
53}
54if (defined $opts{'q'}) {
55 $debug=-1;
56}
57if (defined $opts{'l'}) {
58 open(LOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!";
59 $LOG = *LOG;
60 $debug = 0 if ($debug == -1);
61 }
62# Handles project name if any
63if (defined $opts{'p'}) {
64 $ENV{'PBPROJ'} = env_init($opts{'p'});
65} else {
66 $ENV{'PBPROJ'} = env_init();
67}
68# Handles test option
69if (defined $opts{'t'}) {
70 $test = "TRUE";
71 # Works only for SVN
72 $option = "-r BASE";
73}
74
75# Get Action
76$action = shift @ARGV;
77die syntax() if (not defined $action);
78
79print $LOG "Project $ENV{'PBPROJ'}\n" if ($debug >= 0);
80print $LOG "Action: $action\n" if ($debug >= 0);
81
82# Act depending on action
83if ($action =~ /^cms2build$/) {
84 my $ptr = get_pkg();
85 @pkgs = @$ptr;
86 cms_init();
87
88 foreach my $pbpkg (@pkgs) {
89 if (-f "$ENV{'PBROOT'}/$pbpkg/VERSION") {
90 open(V,"$ENV{'PBROOT'}/$pbpkg/VERSION") || die "Unable to open $ENV{'PBROOT'}/$pbpkg/VERSION";
91 $pbver = <V>;
92 chomp($pbver);
93 close(V);
94 } else {
95 $pbver = $ENV{'PBVER'};
96 }
97
98 if (-f "$ENV{'PBROOT'}/$pbpkg/TAG") {
99 open(T,"$ENV{'PBROOT'}/$pbpkg/TAG") || die "Unable to open $ENV{'PBROOT'}/$pbpkg/TAG";
100 $pbtag = <T>;
101 chomp($pbtag);
102 close(T);
103 } else {
104 $pbtag = $ENV{'PBTAG'};
105 }
106 $pbrev = $ENV{'PBREVISION'};
107 print $LOG "\n" if ($debug >= 0);
108 print $LOG "Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n" if ($debug >= 0);
109 die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
110 # Clean up dest if necessary. The export will recreate it
111 my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver";
112 pbrm_rf($dest) if (-d $dest);
113
114 # Export CMS tree for the concerned package to dest
115 # And generate some additional files
116 $OUTPUT_AUTOFLUSH=1;
117 print $LOG "$ENV{'PBCMSEXP'} of $pbpkg..." if ($debug >= 0);
118 # computes in which dir we have to work
119 my $dir = $defpkgdir{$pbpkg};
120 $dir = $extpkgdir{$pbpkg} if (not defined $dir);
121 system("$ENV{'PBCMSEXP'} $option $ENV{'PBROOT'}/$dir $dest 1>/dev/null");
122 if ($? == -1) {
123 print $LOG "failed to execute: $!\n" if ($debug >= 0);
124 } elsif ($? & 127) {
125 printf $LOG "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without' if ($debug >= 0);
126 } else {
127 print $LOG " OK\n" if ($debug >= 0);
128 }
129
130 # Creates a REVISION file
131 open(R,"> $dest/REVISION") || die "Unable to create $dest/REVISION";
132 print R "$pbrev\n";
133 close(R);
134
135 # Extract cms log history and store it
136 system("$ENV{'PBCMSLOG'} $option $ENV{'PBROOT'}/$dir > $dest/$ENV{'PBCMSLOGFILE'}");
137 print $LOG "$ENV{'PBCMSLOG'} of $pbpkg..." if ($debug >= 0);
138 if ($? == -1) {
139 print $LOG "failed to execute: $!\n" if ($debug >= 0);
140 } elsif ($? & 127) {
141 printf $LOG "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without' if ($debug >= 0);
142 } else {
143 print $LOG " OK\n" if ($debug >= 0);
144 }
145 my %build;
146 open(D,"$ENV{'PBCONF'}/DISTROS") || die "Unable to find $ENV{'PBCONF'}/DISTROS\n";
147 while (<D>) {
148 my $d = $_;
149 my ($dir,$ver) = split(/_/,$d);
150 chomp($ver);
151 my ($ddir, $dver, $dfam, $dtype, $dsuf) = distro_init($dir,$ver);
152 print $LOG "DEBUG: distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $dsuf)."\n" if ($debug >= 1);
153 print $LOG "DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n" if ($debug >= 1);
154
155 # Filter build files from the less precise up to the most with overloading
156 # Filter all files found, keeping the name, and generating in dest
157
158 # Find all build files first relatively to PBROOT
159 my %bfiles;
160 print $LOG "DEBUG dir: $ENV{'PBCONF'}/$pbpkg\n" if ($debug >= 1);
161 $build{"$ddir-$dver"} = "yes";
162 if (-d "$ENV{'PBCONF'}/$pbpkg/$dtype") {
163 opendir(BDIR,"$ENV{'PBCONF'}/$pbpkg/$dtype") || die "Unable to open dir $ENV{'PBCONF'}/$pbpkg/$dtype: $!";
164 foreach my $f (readdir(BDIR)) {
165 next if ($f =~ /^\./);
166 $bfiles{$f} = "$ENV{'PBCONF'}/$pbpkg/$dtype/$f";
167 $bfiles{$f} =~ s~$ENV{'PBROOT'}~~;
168 }
169 closedir(BDIR);
170 } elsif (-d "$ENV{'PBCONF'}/$pbpkg/$dfam") {
171 opendir(BDIR,"$ENV{'PBCONF'}/$pbpkg/$dfam") || die "Unable to open dir $ENV{'PBCONF'}/$pbpkg/$dfam: $!";
172 foreach my $f (readdir(BDIR)) {
173 next if ($f =~ /^\./);
174 $bfiles{$f} = "$ENV{'PBCONF'}/$pbpkg/$dfam/$f";
175 $bfiles{$f} =~ s~$ENV{'PBROOT'}~~;
176 }
177 closedir(BDIR);
178 } elsif (-d "$ENV{'PBCONF'}/$pbpkg/$ddir") {
179 opendir(BDIR,"$ENV{'PBCONF'}/$pbpkg/$ddir") || die "Unable to open dir $ENV{'PBCONF'}/$pbpkg/$ddir: $!";
180 foreach my $f (readdir(BDIR)) {
181 next if ($f =~ /^\./);
182 $bfiles{$f} = "$ENV{'PBCONF'}/$pbpkg/$ddir/$f";
183 $bfiles{$f} =~ s~$ENV{'PBROOT'}~~;
184 }
185 closedir(BDIR);
186 } elsif (-d "$ENV{'PBCONF'}/$pbpkg/$ddir-$dver") {
187 opendir(BDIR,"$ENV{'PBCONF'}/$pbpkg/$ddir-$dver") || die "Unable to open dir $ENV{'PBCONF'}/$pbpkg/$ddir-$dver: $!";
188 foreach my $f (readdir(BDIR)) {
189 next if ($f =~ /^\./);
190 $bfiles{$f} = "$ENV{'PBCONF'}/$pbpkg/$ddir-$dver/$f";
191 $bfiles{$f} =~ s~$ENV{'PBROOT'}~~;
192 }
193 closedir(BDIR);
194 } else {
195 $build{"$ddir-$dver"} = "no";
196 next;
197 }
198 print $LOG "DEBUG bfiles: ".Dumper(\%bfiles)."\n" if ($debug >= 1);
199
200 # Get all filters to apply
201 # They're cumulative from less specific to most specific
202 # suffix is .pbf
203 my @ffiles;
204 my ($ffile0, $ffile1, $ffile2, $ffile3);
205 if (-d "$ENV{'PBCONF'}/$pbpkg/pbfilter") {
206 $ffile0 = "$ENV{'PBCONF'}/$pbpkg/pbfilter/$dtype.pbf" if (-f "$ENV{'PBCONF'}/$pbpkg/pbfilter/$dtype.pbf");
207 $ffile1 = "$ENV{'PBCONF'}/$pbpkg/pbfilter/$dfam.pbf" if (-f "$ENV{'PBCONF'}/$pbpkg/pbfilter/$dfam.pbf");
208 $ffile2 = "$ENV{'PBCONF'}/$pbpkg/pbfilter/$ddir.pbf" if (-f "$ENV{'PBCONF'}/$pbpkg/pbfilter/$ddir.pbf");
209 $ffile3 = "$ENV{'PBCONF'}/$pbpkg/pbfilter/$ddir-$dver.pbf" if (-f "$ENV{'PBCONF'}/$pbpkg/pbfilter/$ddir-$dver.pbf");
210 push @ffiles,$ffile0 if (defined $ffile0);
211 push @ffiles,$ffile1 if (defined $ffile1);
212 push @ffiles,$ffile2 if (defined $ffile2);
213 push @ffiles,$ffile3 if (defined $ffile3);
214 }
215 my $config = AppConfig->new({
216 # Auto Create variables mentioned in Conf file
217 CREATE => 1,
218 DEBUG => 0,
219 GLOBAL => {
220 # Each conf item is a hash
221 ARGCOUNT => AppConfig::ARGCOUNT_HASH
222 }
223 });
224 my $ptr;
225 if (@ffiles) {
226 print $LOG "DEBUG ffiles: ".Dumper(\@ffiles)."\n" if ($debug >= 1);
227 $config->file(@ffiles);
228 $ptr = $config->get("filter");
229 print $LOG "DEBUG f:".Dumper($ptr)."\n" if ($debug >= 1);
230 } else {
231 $ptr = { };
232 }
233
234 # Apply now all the filters on all the files concerned
235 # All files are relative to PBROOT
236 # destination dir depends on the type of file
237 if (defined $ptr) {
238 foreach my $f (values %bfiles) {
239 filter_file($f,$ptr,"$dest/pbconf/$ddir-$dver/".basename($f),$pbpkg,$dtype,$dsuf);
240 }
241 foreach my $f (keys %filteredfiles) {
242 filter_file($f,$ptr,"$dest/$f",$pbpkg,$dtype,$dsuf);
243 }
244 }
245 }
246 if ($debug >= 0) {
247 my @found;
248 my @notfound;
249 foreach my $b (keys %build) {
250 push @found,$b if ($build{$b} =~ /yes/);
251 push @notfound,$b if ($build{$b} =~ /no/);
252 }
253 print $LOG "Build files generated for ".join(',',@found)."\n";
254 print $LOG "No Build files found for ".join(',',@notfound)."\n";
255 }
256 close(D);
257 # Prepare the dest directory for archive
258 if (-x "$ENV{'PBCONF'}/$pbpkg/pbpkginit") {
259 print $LOG " Executing $ENV{'PBCONF'}/$pbpkg/pbinit...\n" if ($debug >= 0);
260 system("cd $dest ; $ENV{'PBCONF'}/$pbpkg/pbinit");
261 if ($? == -1) {
262 print $LOG "failed to execute: $!\n" if ($debug >= 0);
263 } elsif ($? & 127) {
264 printf $LOG "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without' if ($debug >= 0);
265 } else {
266 print $LOG " OK\n" if ($debug >= 0);
267 }
268 }
269 # Archive dest dir
270 chdir "$ENV{'PBDESTDIR'}";
271 print $LOG "Creating $pbpkg tar files (gzip... " if ($debug >= 0);
272 # Possibility to look at PBSRC to guess more the filename
273 system("tar cfphz $pbpkg-$pbver.tar.gz $pbpkg-$pbver");
274 if ($? == -1) {
275 print $LOG "failed to execute: $!\n" if ($debug >= 0);
276 } elsif ($? & 127) {
277 printf $LOG "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without' if ($debug >= 0);
278 } else {
279 print $LOG " OK)\n" if ($debug >= 0);
280 print $LOG "Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz\n" if ($debug >= 0);
281 # Keep track of what is generated for build2pkg default
282 open(LAST,"> $ENV{'PBDESTDIR'}/LAST") || die "Unable to create $ENV{'PBDESTDIR'}/LAST";
283 print LAST "$pbver-$pbtag\n";
284 close(LAST);
285 }
286 }
287} elsif ($action =~ /^build2pkg$/) {
288 # Check whether we have a specific version to build
289 my $vertag = shift @ARGV;
290 if (not defined $vertag) {
291 open(LAST,"$ENV{'PBDESTDIR'}/LAST") || die "Unable to open $ENV{'PBDESTDIR'}/LAST\nYou may want to precise as parameter version-tag";
292 $vertag = <LAST>;
293 chomp($vertag);
294 close(LAST);
295 }
296 ($pbver,$pbtag) = split(/-/,$vertag);
297
298 # Get list of packages to build
299 my $ptr = get_pkg();
300 @pkgs = @$ptr;
301
302 # Get the running distro to build on
303 my ($ddir, $dver, $dfam, $dtype, $dsuf) = distro_init();
304 print $LOG "DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $dsuf))."\n" if ($debug >= 1);
305
306 chdir "$ENV{'PBBUILDDIR'}";
307 foreach my $pbpkg (@pkgs) {
308 my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz";
309 print $LOG "Handling source file $src\n" if ($debug >= 0);
310
311 if ($dtype eq "rpm") {
312 # rpm has its own standard build directory
313 $ENV{'PBBUILDDIR'}=`rpmquery --eval '%{_topdir}' 2> /dev/null`;
314 chdir "$ENV{'PBBUILDDIR'}";
315 foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') {
316 pbmkdir_p($d) if (! -d $d) || die "Please ensure that you can write into $ENV{'PBBUILDDIR'}\nSolution: setup _topdir in your ~/.rpmmacros or\nchown the $ENV{'PBBUILDDIR'} directory to your uid";
317 }
318
319 # We need to first extract the spec file
320 symlink "$src","SOURCES/".basename($src) || die "Unable to symlink $src in SOURCES";;
321 extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","SPECS");
322
323 # set LANGUAGE to check for correct log messages
324 $ENV{'LANGUAGE'}="C";
325 system("ls -R ");
326 system("cd SPECS ; rpmbuild -ba *.spec");
327
328 } elsif ($dtype eq "tgz") {
329 pbmkdir_p("$ENV{'PBBUILDDIR'}/install") if (! -d "$ENV{'PBBUILDDIR'}/install");
330 } elsif ($dtype eq "ebuild") {
331 pbmkdir_p("$ENV{'PBBUILDDIR'}/portage") if (! -d "$ENV{'PBBUILDDIR'}/portage");
332 } else {
333 }
334 }
335} else {
336 print $LOG "'$action' is not available\n";
337 syntax();
338}
339
340# Function which applies filter on files
341sub filter_file {
342
343my $f=shift;
344my $ptr=shift;
345my %filter=%$ptr;
346my $destfile=shift;
347my $pbpkg=shift;
348my $dtype=shift;
349my $dsuf=shift;
350
351print $LOG "DEBUG: From $f to $destfile\n" if ($debug >= 1);
352pbmkdir_p(dirname($destfile)) if (! -d dirname($destfile));
353open(DEST,"> $destfile") || die "Unable to create $destfile";
354open(FILE,"$ENV{'PBROOT'}/$f") || die "Unable to open $f: $!";
355while (<FILE>) {
356 my $line = $_;
357 foreach my $s (keys %filter) {
358 # Process single variables
359 print $LOG "DEBUG filter{$s}: $filter{$s}\n" if ($debug > 1);
360 my $tmp = $filter{$s};
361 next if (not defined $tmp);
362 # Expand variables if any single one found
363 if ($tmp =~ /\$/) {
364 eval { $tmp =~ s/(\$\w+)/$1/eeg };
365 # special case for ChangeLog
366 } elsif (($tmp =~ /^yes$/) && ($s =~ /^PBLOG$/) && ($line =~ /^PBLOG$/)) {
367 my $p = $defpkgdir{$pbpkg};
368 $p = $extpkgdir{$pbpkg} if (not defined $p);
369 changelog($dtype, $pbpkg, $pbtag, $dsuf, $p, \*DEST);
370 $tmp = "";
371 }
372 $line =~ s|$s|$tmp|;
373 }
374 print DEST $line;
375}
376close(FILE);
377close(DEST);
378}
379
380sub get_pkg {
381
382my @pkgs;
383
384# Get packages list
385if (not defined $ARGV[0]) {
386 @pkgs = keys %defpkgdir;
387} elsif ($ARGV[0] =~ /^all$/) {
388 @pkgs = keys %defpkgdir;
389 if (defined %extpkgdir) {
390 my $k = keys %extpkgdir;
391 if (defined $k) {
392 push(@pkgs, keys %extpkgdir);
393 }
394 }
395} else {
396 @pkgs = @ARGV;
397}
398print $LOG "Packages: ".join(',',@pkgs)."\n" if ($debug >= 0);
399return(\@pkgs);
400}
401
402sub extract_build_files {
403
404my $src=shift;
405my $dir=shift;
406my $ddir=shift;
407
408print $LOG "Extracting build files... " if ($debug >= 0);
409system("tar xfz $src $dir >/dev/null");
410if ($? == -1) {
411 print $LOG "failed to execute: $!\n" if ($debug >= 0);
412} elsif ($? & 127) {
413 printf $LOG "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without' if ($debug >= 0);
414} else {
415 print $LOG " OK\n" if ($debug >= 0);
416}
417opendir(DIR,"$dir") || die "Unable to open directory $dir";
418foreach my $f (readdir(DIR)) {
419 next if ($f =~ /^\./);
420 move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
421 print $LOG "mv $dir/$f .\n" if ($debug >= 1);
422}
423closedir(DIR);
424# Not enough but still a first cleanup
425pbrm_rf("$dir");
426}
427
428sub syntax {
429
430 print "Syntax: pb [-vhqt][-p project] <action> [<params>...]\n";
431 print "\n";
432 print "-h : This help file\n";
433 print "-q : Quiet mode\n";
434 print "-t : Test mode (not done yet)\n";
435 print "-v : Verbose mode\n";
436 print "\n";
437 print "-p project : Name of the project you're working on\n";
438 print " (or use the env variable PBPROJ) \n";
439 print "\n";
440 print "<action> can be:\n";
441 print "\n";
442 print "\tcms2build: Create a tar file of the project under your CMS\n";
443 print "\t CMS supported are SVN and CVS\n";
444 print "\t parameters are packages to build\n";
445 print "\t if not using default list\n";
446 print "\n";
447 print "\tbuild2pkg: Create packages for your running distribution \n";
448 print "\t first parameter is version-tag to build\n";
449 print "\t if not using default version-tag\n";
450 print "\t following parameters are packages to build\n";
451 print "\t if not using default list\n";
452 print "\n";
453 print "\n";
454}
Note: See TracBrowser for help on using the repository browser.