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

Last change on this file since 49 was 49, checked in by Bruno Cornec, 13 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.