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

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

Big renaming to be more perlish
Single module Base contains all routines except when detaching makes sense

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