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

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

conf file is now in the home directory to allow for multi user usage of pb
cms2build and build2pkg are working roughly for pb
Next test with mondo

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