source: ProjectBuilder/devel/pb/bin/pb@ 68

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

Remove use of PBTOPDIR useless
delivery dir is cleaned of dir in it only now.
One level less generated during delivery (easier)

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