source: devel/pb/bin/pb @ 331

Last change on this file since 331 was 331, checked in by bruno, 11 years ago
  • Improvements for CMS support in 0.9.x serie (lots on CVS)
  • Use pod for pb documentation (modules to be done)
  • Use Getopt::Long and support now long options
  • pb_syntax now uses pod2usage
  • Property svn:executable set to *
File size: 43.7 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::Long qw(:config auto_abbrev no_ignore_case);
14use Pod::Usage;
15use Data::Dumper;
16use English;
17use File::Basename;
18use File::Copy;
19use Time::localtime qw(localtime);
20use POSIX qw(strftime);
21
22# Global variables
23use lib qw (lib);
24use ProjectBuilder::Distribution;
25use ProjectBuilder::Version;
26use ProjectBuilder::Base;
27
28my %opts;                   # CLI Options
29my $action;                 # action to realize
30my $test = "FALSE";         # Not used
31my $force = 0;              # Force VE/VM rebuild
32my $option = "";            # Not used
33my @pkgs;                   # list of packages
34my $pbtag;                  # Global Tag variable
35my $pbver;                  # Global Version variable
36my $pbscript;               # Name of the script
37my %pbver;                  # per package
38my %pbtag;                  # per package
39my $pbrev;                  # Global REVISION variable
40my $pbaccount;              # Login to use to connect to the VM
41my $pbport;                 # Port to use to connect to the VM
42my $newver;                 # New version to create
43my $iso;                    # ISO image for the VM to create
44
45my @date = pb_get_date();
46my $pbdate = strftime("%Y-%m-%d", @date);
47
48# ---------------------------------------------------------------------------
49
50=pod
51
52=head1 NAME
53
54pb, aka project-builder.org - builds packages for your projects
55
56=head1 DESCRIPTION
57
58pb helps you build various packages directly from your project sources.
59Those sources could be handled by a CMS (Configuration Management System)
60such as Subversion, CVS, ... or being a simple reference to a compressed tar file.
61It's based on a set of configuration files, a set of provided macros to help
62you keeping build files as generic as possible. For example, a single .spec
63file should be required to generate for all rpm based distributions, even
64if you could also have multiple .spec files if required.
65
66=head1 SYNOPSIS
67
68pb [-vhq][-r pbroot][-p project][[-s script -a account -P port] -m \"mach-1[,...]\"][-i iso] <action> [<pkg1> ...]
69
70pb [--verbose][--help][--man][--quiet][--revision pbroot][--project project][[--script script --account account --port port] --machine \"mach-1[,...]\"][--iso iso] <action> [<pkg1> ...]
71
72=head1 OPTIONS
73
74=over 4
75
76=item B<-v|--verbose>
77
78Print a brief help message and exits.
79
80=item B<-q|--quiet>
81
82Do not print any output.
83
84=item B<-h|--help>
85
86Print a brief help message and exits.
87
88=item B<--man>
89
90Prints the manual page and exits.
91
92=item B<-m|--machine machine1[,machine2,...]>
93
94Name of the Virtual Machines (VM) or Virtual Environments (VE) you want to build on (coma separated).
95All if none precised (or use the env variable PBV).
96
97=item B<-s|--script script>
98
99Name of the script you want to execute on the related VMs or VEs.
100
101=item B<-i|--iso iso_image>
102
103Name of the ISO image of the distribution you want to install on the related VMs.
104
105=item B<-a|--account account>
106
107Name of the account to use to connect on the related VMs.
108
109=item B<-P|--port port_number>
110
111Port number to use to connect on the related VMs.\n";
112
113=item B<-p|--project project_name>
114
115Name of the project you're working on (or use the env variable PBPROJ)
116
117=item B<-r|--revision revision>
118
119Path Name of the project revision under the CMS (or use the env variable PBROOT)
120
121=item B<-V|--version new_version>
122
123New version of the project to create based on the current one.
124
125=back
126
127=head1 ARGUMENTS
128
129<action> can be:
130
131=over 4
132
133=item B<cms2build>
134
135Create tar files for the project under your CMS.
136CMS supported are SVN and CVS
137parameters are packages to build
138if not using default list
139
140=item B<build2pkg>
141
142Create packages for your running distribution
143
144=item B<cms2pkg>
145
146cms2build + build2pkg
147
148=item B<build2ssh>
149
150Send the tar files to a SSH host
151
152=item B<cms2ssh>
153
154cms2build + build2ssh
155
156=item B<pkg2ssh>
157
158Send the packages built to a SSH host
159
160=item B<build2vm>
161
162Create packages in VMs, launching them if needed
163and send those packages to a SSH host once built
164VM type supported are QEMU
165
166=item B<build2ve>
167
168Create packages in VEs, creating it if needed
169and send those packages to a SSH host once built
170
171=item B<cms2vm>
172
173cms2build + build2vm
174
175=item B<cms2ve>
176
177cms2build + build2ve
178
179=item B<launchvm>
180
181Launch one virtual machine
182
183=item B<launchve>
184
185Launch one virtual environment
186
187=item B<script2vm>
188
189Launch one virtual machine if needed
190and executes a script on it
191
192=item B<script2ve>
193
194Execute a script in a virtual environment
195
196=item B<newvm>
197
198Create a new virtual machine
199
200=item B<newve>
201
202Create a new virtual environment
203
204=item B<newver>
205
206Create a new version of the project derived
207from the current one
208
209=item B<newproj>
210
211Create a new project and a template set of
212configuration files under pbconf
213
214=back
215
216<pkgs> can be a list of packages, the keyword 'all' or nothing, in which case the default list of packages is taken (corresponding to the defpkgdir list of arguments in the configuration file).
217
218=head1 WEB SITES
219
220The main Web site of the project is available at L<http://www.project-builder.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
221
222=head1 USER MAILING LIST
223
224None exists for the moment.
225
226=head1 CONFIGURATION FILES
227
228Each pb user may have a configuration in F<$HOME/.pbrc>. The values in this file may overwrite any other configuration file value.
229
230Here is an example of such a configuration file:
231
232 #
233 # Define for each project the URL of its pbconf repository
234 # No default option allowed here as they need to be all different
235 #
236 # URL of the pbconf content
237 # This is the format of a classical URL with the extension of additional schema such as
238 # svn+ssh, cvs+ssh, ...
239 #
240 pbconfurl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe/pbconf
241
242 # This is normaly defined in the project's configuration file
243 # Url of the project
244 #
245 pburl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe
246 
247 # All these URLs needs to be defined here as the are the entry point
248 # for how to build packages for the project
249 #
250 pbconfurl pb = svn+ssh://svn.project-builder.org/mondo/svn/pb/pbconf
251 pbconfurl mondorescue = svn+ssh://svn.project-builder.org/mondo/svn/project-builder/mondorescue/pbconf
252 pbconfurl collectl = svn+ssh://bruno@svn.mondorescue.org/mondo/svn/project-builder/collectl/pbconf
253 pbconfurl netperf = svn+ssh://svn.mondorescue.org/mondo/svn/project-builder/netperf/pbconf
254 
255 # Under that dir will take place everything related to pb
256 # If you want to use VMs/chroot/..., then use $ENV{'HOME'} to make it portable
257 # to your VMs/chroot/...
258 # if not defined then /var/cache
259 pbdefdir default = $ENV{'HOME'}/project-builder
260 pbdefdir pb = $ENV{'HOME'}
261 pbdefdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
262 pbdefdir mondorescue = $ENV{'HOME'}/mondo/svn
263 
264 # pbconfdir points to the directory where the CMS content of the pbconfurl is checked out
265 # If not defined, pbconfdir is under pbdefdir/pbproj/pbconf
266 pbconfdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs/pbconf
267 pbconfdir mondorescue = $ENV{'HOME'}/mondo/svn/pbconf
268 
269 # pbdir points to the directory where the CMS content of the pburl is checked out
270 # If not defined, pbdir is under pbdefdir/pbproj
271 # Only defined if we have access to the dev of the project
272 pbdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
273 pbdir mondorescue = $ENV{'HOME'}/mondo/svn
274 
275 # -daemonize doesn't work with qemu 0.8.2
276 vmopt default = -m 384
277
278=head1 AUTHORS
279
280The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
281
282=head1 COPYRIGHT
283
284Project-Builder.org is distributed under the GPL v2.0 license
285described in the file C<COPYING> included with the distribution.
286
287=cut
288
289# ---------------------------------------------------------------------------
290
291# Old syntax
292#getopts('a:fhi:l:m:P:p:qr:s:vV:',\%opts);
293
294my ($projectbuilderver,$projectbuilderrev) = pb_version_init();
295
296GetOptions("help|?|h" => \$opts{'h'}, 
297        "man" => \$opts{'man'},
298        "verbose|v+" => \$opts{'v'},
299        "quiet|q" => \$opts{'q'},
300        "log-files|l=s" => \$opts{'l'},
301        "force|f" => \$opts{'f'},
302        "account|a=s" => \$opts{'a'},
303        "revision|r=s" => \$opts{'r'},
304        "script|s=s" => \$opts{'s'},
305        "machines|mock|m=s" => \$opts{'m'},
306        "port|P=i" => \$opts{'P'},
307        "project|p=s" => \$opts{'p'},
308        "iso|i=s" => \$opts{'i'},
309        "version|V=s" => \$opts{'V'},
310) || pb_syntax(-1,0);
311
312if (defined $opts{'h'}) {
313    pb_syntax(0,1);
314}
315if (defined $opts{'man'}) {
316    pb_syntax(0,2);
317}
318if (defined $opts{'v'}) {
319    $debug = $opts{'v'};
320    pb_log(0,"Debug value: $debug\n");
321}
322if (defined $opts{'f'}) {
323    $force=1;
324}
325if (defined $opts{'q'}) {
326    $debug=-1;
327}
328if (defined $opts{'l'}) {
329    open(LOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!";
330    $LOG = *LOG;
331    $debug = 0  if ($debug == -1);
332    }
333pb_log_init($debug, $LOG);
334
335# Handle root of the project if defined
336if (defined $opts{'r'}) {
337    $ENV{'PBROOT'} = $opts{'r'};
338}
339# Handle virtual machines if any
340if (defined $opts{'m'}) {
341    $ENV{'PBV'} = $opts{'m'};
342}
343if (defined $opts{'s'}) {
344    $pbscript = $opts{'s'};
345}
346if (defined $opts{'a'}) {
347    $pbaccount = $opts{'a'};
348}
349if (defined $opts{'P'}) {
350    $pbport = $opts{'P'};
351}
352if (defined $opts{'V'}) {
353    $newver = $opts{'V'};
354}
355if (defined $opts{'i'}) {
356    $iso = $opts{'i'};
357}
358
359# Get Action
360$action = shift @ARGV;
361die pb_syntax(-1,1) if (not defined $action);
362
363my ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir);
364my $pbinit = undef;
365$pbinit = 1 if ($action =~ /^newproj$/);
366
367# Handles project name if any
368# And get global params
369if (defined $opts{'p'}) {
370    ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir) 
371    = pb_env_init($opts{'p'},$pbinit);
372} else {
373    ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir) 
374    = pb_env_init(undef,$pbinit);
375}
376
377pb_log(0,"Project: $ENV{'PBPROJ'}\n");
378pb_log(0,"Action: $action\n");
379
380# Keep those project values to store them at the end each time
381my $pbprojtag = $ENV{'PBTAG'};
382my $pbprojver = $ENV{'PBVER'};
383
384# Act depending on action
385if ($action =~ /^cms2build$/) {
386    pb_cms2build();
387} elsif ($action =~ /^build2pkg$/) {
388    pb_build2pkg();
389} elsif ($action =~ /^cms2pkg$/) {
390    pb_cms2build();
391    pb_build2pkg();
392} elsif ($action =~ /^build2ssh$/) {
393    pb_build2ssh();
394} elsif ($action =~ /^cms2ssh$/) {
395    pb_cms2build();
396    pb_build2ssh();
397} elsif ($action =~ /^pkg2ssh$/) {
398    pb_pkg2ssh();
399} elsif ($action =~ /^build2ve$/) {
400    pb_build2v("ve");
401} elsif ($action =~ /^build2vm$/) {
402    pb_build2v("vm");
403} elsif ($action =~ /^cms2ve$/) {
404    pb_cms2build();
405    pb_build2v("ve");
406} elsif ($action =~ /^cms2vm$/) {
407    pb_cms2build();
408    pb_build2v("vm");
409} elsif ($action =~ /^launchvm$/) {
410    pb_launchv("vm",$ENV{'PBV'},0);
411} elsif ($action =~ /^launchve$/) {
412    pb_launchv("ve",$ENV{'PBV'},0);
413} elsif ($action =~ /^script2vm$/) {
414    pb_script2v($pbscript,"vm");
415} elsif ($action =~ /^script2ve$/) {
416    pb_script2v($pbscript,"ve");
417} elsif ($action =~ /^newver$/) {
418    pb_newver();
419} elsif ($action =~ /^newve$/) {
420    pb_launchv("ve",$ENV{'PBV'},1);
421} elsif ($action =~ /^newvm$/) {
422    pb_launchv("vm",$ENV{'PBV'},1);
423} elsif ($action =~ /^newproj$/) {
424    # Nothing to do - already done in pb_env_init
425} elsif ($action =~ /^clean$/) {
426} else {
427    pb_log(0,"\'$action\' is not available\n");
428    pb_syntax(-2,1);
429}
430
431sub pb_cms2build {
432
433    my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
434    @pkgs = @$ptr;
435    my ($uri) = pb_conf_get("pburl");
436    my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri->{$ENV{'PBPROJ'}});
437
438    #
439    # Check project cms compliance
440    #
441    pb_cms_compliant("pbdir",'PBDIR',"$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}",$uri->{$ENV{'PBPROJ'}},$pbinit);
442
443    # Some variable initialization depending on CMS type
444    pb_cms_init($scheme);
445
446    my ($pkgv, $pkgt) = pb_conf_get_if("pkgver","pkgtag");
447
448    # declare packager for filtering
449    my ($tmp) = pb_conf_get("pbpackager");
450    my $pbpackager = $tmp->{$ENV{'PBPROJ'}};
451
452    foreach my $pbpkg (@pkgs) {
453        $ENV{'PBPKG'} = $pbpkg;
454        $ENV{'PBVER'} = $pbprojver;
455        $ENV{'PBTAG'} = $pbprojtag;
456        if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) {
457            $pbver = $pkgv->{$pbpkg};
458            $ENV{'PBVER'} = $pbver;
459        } else {
460            $pbver = $ENV{'PBVER'};
461        }
462        if ((defined $pkgt) && (defined $pkgt->{$pbpkg})) {
463            $pbtag = $pkgt->{$pbpkg};
464            $ENV{'PBTAG'} = $pbtag;
465        } else {
466            $pbtag = $ENV{'PBTAG'};
467        }
468
469        $pbrev = $ENV{'PBREVISION'};
470        pb_log(0,"\n");
471        pb_log(0,"Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n");
472        die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
473        # Clean up dest if necessary. The export will recreate it
474        my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver";
475        pb_rm_rf($dest) if (-d $dest);
476
477        # Export CMS tree for the concerned package to dest
478        # And generate some additional files
479        $OUTPUT_AUTOFLUSH=1;
480
481        # computes in which dir we have to work
482        my $dir = $defpkgdir->{$pbpkg};
483        $dir = $extpkgdir->{$pbpkg} if (not defined $dir);
484        pb_log(2,"def:".Dumper($defpkgdir)." ext: ".Dumper($extpkgdir)." \n");
485
486        # If it isn't a flat CMS, then we have the choice to export subdir
487        pb_cms_export($uri->{$ENV{'PBPROJ'}},"$ENV{'PBDIR'}/$pbprojver/$dir",$dest);
488
489        # Get project info on authors and log file
490        my $chglog = "$ENV{'PBROOT'}/$pbpkg/pbcl";
491        $chglog = "$ENV{'PBROOT'}/pbcl" if (! -f $chglog);
492        $chglog = undef if (! -f $chglog);
493
494        my $authors = "$ENV{'PBROOT'}/$pbpkg/pbauthors";
495        $authors = "$ENV{'PBROOT'}/pbauthors" if (! -f $authors);
496        $authors = "/dev/null" if (! -f $authors);
497
498        # Extract cms log history and store it
499        if ((defined $chglog) && (! -f "$dest/NEWS")) {
500            pb_log(2,"Generating NEWS file from $chglog\n");
501            copy($chglog,"$dest/NEWS") || die "Unable to create $dest/NEWS";
502        }
503        pb_cms_log($scheme,"$ENV{'PBDIR'}/$pbprojver/$dir",$dest,$chglog,$authors);
504
505        my %build;
506
507        my @pt;
508        @pt = pb_conf_get_if("vmlist","velist");
509        foreach my $d (split(/,/,$pt[0]->{$ENV{'PBPROJ'}}),split(/,/,$pt[1]->{$ENV{'PBPROJ'}})) {
510            my ($name,$ver,$arch) = split(/-/,$d);
511            chomp($arch);
512            my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver);
513            pb_log(2,"DEBUG: distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf)."\n");
514            pb_log(2,"DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n");
515
516            # Filter build files from the less precise up to the most with overloading
517            # Filter all files found, keeping the name, and generating in dest
518
519            # Find all build files first relatively to PBROOT
520            # Find also all specific files referenced in the .pb conf file
521            my %bfiles = ();
522            my %pkgfiles = ();
523            $build{"$ddir-$dver"} = "yes";
524
525            if (-d "$ENV{'PBROOT'}/$pbpkg/$dtype") {
526                pb_list_bfiles("$ENV{'PBROOT'}/$pbpkg/$dtype",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
527            } elsif (-d "$ENV{'PBROOT'}/$pbpkg/$dfam") {
528                pb_list_bfiles("$ENV{'PBROOT'}/$pbpkg/$dfam",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
529            } elsif (-d "$ENV{'PBROOT'}/$pbpkg/$ddir") {
530                pb_list_bfiles("$ENV{'PBROOT'}/$pbpkg/$ddir",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
531            } elsif (-d "$ENV{'PBROOT'}/$pbpkg/$ddir-$dver") {
532                pb_list_bfiles("$ENV{'PBROOT'}/$pbpkg/$ddir-$dver",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
533            } else {
534                $build{"$ddir-$dver"} = "no";
535                next;
536            }
537            pb_log(2,"DEBUG bfiles: ".Dumper(\%bfiles)."\n");
538
539            # Get all filters to apply
540            my $ptr = pb_get_filters($pbpkg, $dtype, $dfam, $ddir, $dver);
541
542            # Apply now all the filters on all the files concerned
543            # destination dir depends on the type of file
544            if (defined $ptr) {
545                foreach my $f (values %bfiles,values %pkgfiles) {
546                    pb_filter_file_pb("$ENV{'PBROOT'}/$f",$ptr,"$dest/pbconf/$ddir-$dver/".basename($f),$dtype,$pbsuf,$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$defpkgdir,$extpkgdir,$pbpackager,$chglog);
547                }
548            }
549        }
550        my @found;
551        my @notfound;
552        foreach my $b (keys %build) {
553            push @found,$b if ($build{$b} =~ /yes/);
554            push @notfound,$b if ($build{$b} =~ /no/);
555        }
556        pb_log(0,"Build files generated for ".join(',',@found)."\n");
557        pb_log(0,"No Build files found for ".join(',',@notfound)."\n") if (@notfound);
558        # Get the generic filter (all.pbf) and
559        # apply those to the non-build files including those
560        # generated by pbinit if applicable
561
562        # Get only all.pbf filter
563        $ptr = pb_get_filters($pbpkg);
564
565        my $liste ="";
566        if (defined $filteredfiles->{$pbpkg}) {
567            foreach my $f (split(/,/,$filteredfiles->{$pbpkg})) {
568                pb_filter_file_inplace($ptr,"$dest/$f",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$pbpackager);
569                $liste = "$f $liste";
570            }
571        }
572        pb_log(2,"Files ".$liste."have been filtered\n");
573
574        # Prepare the dest directory for archive
575        if (-x "$ENV{'PBROOT'}/$pbpkg/pbinit") {
576            pb_filter_file("$ENV{'PBROOT'}/$pbpkg/pbinit",$ptr,"$ENV{'PBTMP'}/pbinit",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$pbpackager);
577            chmod 0755,"$ENV{'PBTMP'}/pbinit";
578            pb_system("cd $dest ; $ENV{'PBTMP'}/pbinit","Executing init script from $ENV{'PBROOT'}/$pbpkg/pbinit");
579        }
580
581        # Archive dest dir
582        chdir "$ENV{'PBDESTDIR'}" || die "Unable to change dir to $ENV{'PBDESTDIR'}";
583        # Possibility to look at PBSRC to guess more the filename
584        pb_system("tar cfz $pbpkg-$pbver.tar.gz $pbpkg-$pbver","Creating $pbpkg tar files compressed");
585        pb_log(2,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz\n");
586
587        # Keep track of what is generated by default
588        open(LAST,"> $ENV{'PBDESTDIR'}/pbrc") || die "Unable to create $ENV{'PBDESTDIR'}/pbrc";
589        #print LAST "pbroot $pbprojver-$pbprojtag = $ENV{'PBROOT'}\n";
590        # Why not use pbproj ?
591        print LAST "pbroot $ENV{'PBPROJ'} = $ENV{'PBROOT'}\n";
592        close(LAST);
593
594        # Keep track of per package version
595        my ($pkg) = pb_conf_read_if("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
596        $pkg = { } if (not defined $pkg);
597        if ((not defined $pkg->{$pbpkg}) || ($pkg->{$pbpkg} ne "$pbver-$pbtag")) {
598            $pkg->{$pbpkg} = "$pbver-$pbtag";
599        }
600
601        pb_log(2,"DEBUG pkg: ".Dumper($pkg)."\n");
602        open(PKG,"> $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb") || die "Unable to create $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb";
603        foreach my $p (keys %$pkg) {
604            print PKG "pbpkg $p = $pkg->{$p}\n";
605        }
606        close(PKG);
607
608        # Final cleanup
609        pb_rm_rf($dest) if (-d $dest);
610    }
611}
612
613sub pb_build2pkg {
614
615    # Get list of packages to build
616    my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
617    @pkgs = @$ptr;
618
619    # Get the running distro to build on
620    my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init();
621    pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n");
622
623    # Get content saved in cms2build
624    my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
625    $pkg = { } if (not defined $pkg);
626
627    # declare packager (via env var in VM/VE
628    my $pbpackager;
629    if (not defined $ENV{'PBPACKAGER'}) {
630        my ($tmp) = pb_conf_get("pbpackager");
631        $pbpackager = $tmp->{$ENV{'PBPROJ'}};
632    } else {
633        $pbpackager = $ENV{'PBPACKAGER'};
634    }
635
636    chdir "$ENV{'PBBUILDDIR'}";
637    my $made = ""; # pkgs made during build
638    foreach my $pbpkg (@pkgs) {
639        my $vertag = $pkg->{$pbpkg};
640        # get the version of the current package - maybe different
641        ($pbver,$pbtag) = split(/-/,$vertag);
642
643        my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz";
644        pb_log(2,"Source file: $src\n");
645
646        pb_log(2,"Working directory: $ENV{'PBBUILDDIR'}\n");
647        if ($dtype eq "rpm") {
648            foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') {
649                if (! -d "$ENV{'PBBUILDDIR'}/$d") {
650                pb_mkdir_p("$ENV{'PBBUILDDIR'}/$d") || die "Please ensure that you can write into $ENV{'PBBUILDDIR'} to create $d\nchown the $ENV{'PBBUILDDIR'} directory to your uid";
651                }
652            }
653
654            # Remove in case a previous link/file was there
655            unlink "$ENV{'PBBUILDDIR'}/SOURCES/".basename($src);
656            symlink "$src","$ENV{'PBBUILDDIR'}/SOURCES/".basename($src) || die "Unable to symlink $src in $ENV{'PBBUILDDIR'}/SOURCES";
657            # We need to first extract the spec file
658            my @specfile;
659            @specfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$ENV{'PBBUILDDIR'}/SPECS");
660
661            pb_log(2,"specfile: ".Dumper(\@specfile)."\n");
662            # set LANGUAGE to check for correct log messages
663            $ENV{'LANGUAGE'}="C";
664            foreach my $f (@specfile) {
665                if ($f =~ /\.spec$/) {
666                    pb_system("rpmbuild --define \'packager $pbpackager\' --define \"_topdir $ENV{'PBBUILDDIR'}\" -ba $f","Building package with $f under $ENV{'PBBUILDDIR'}");
667                    last;
668                }
669            }
670            $made="$made RPMS/*/$pbpkg-$pbver-$pbtag$pbsuf.*.rpm SRPMS/$pbpkg-$pbver-$pbtag$pbsuf.src.rpm";
671            if (-f "/usr/bin/rpmlint") {
672                pb_system("rpmlint $made","Checking validity of rpms with rpmlint");
673            }
674        } elsif ($dtype eq "deb") {
675            chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
676            pb_system("tar xfz $src","Extracting sources");
677
678            chdir "$pbpkg-$pbver" || die "Unable to chdir to $pbpkg-$pbver";
679            pb_rm_rf("debian");
680            symlink "pbconf/$ddir-$dver","debian" || die "Unable to symlink to pbconf/$ddir-$dver";
681            chmod 0755,"debian/rules";
682            pb_system("dpkg-buildpackage -us -uc -rfakeroot","Building package");
683            $made="$made $pbpkg"."_*.deb $pbpkg"."_*.dsc $pbpkg"."_*.tar.gz";
684            if (-f "/usr/bin/lintian") {
685                pb_system("lintian $made","Checking validity of debs with lintian");
686            }
687        } elsif ($dtype eq "ebuild") {
688            my @ebuildfile;
689            # For gentoo we need to take pb as subsystem name
690            # We put every apps here under sys-apps. hope it's correct
691            # We use pb's home dir in order o have a single OVERLAY line
692            my $tmpd = "$ENV{'HOME'}/portage/pb/sys-apps/$pbpkg";
693            pb_mkdir_p($tmpd) if (! -d "$tmpd");
694            pb_mkdir_p("$ENV{'HOME'}/portage/distfiles") if (! -d "$ENV{'HOME'}/portage/distfiles");
695
696            # We need to first extract the ebuild file
697            @ebuildfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$tmpd");
698
699            # Prepare the build env for gentoo
700            my $found = 0;
701            my $pbbd = $ENV{'HOME'};
702            $pbbd =~ s|/|\\/|g;
703            if (-r "/etc/make.conf") {
704                open(MAKE,"/etc/make.conf");
705                while (<MAKE>) {
706                    $found = 1 if (/$pbbd\/portage/);
707                }
708                close(MAKE);
709            }
710            if ($found == 0) {
711                pb_system("sudo sh -c 'echo PORTDIR_OVERLAY=\"$ENV{'HOME'}/portage\" >> /etc/make.conf'");
712            }
713            #$found = 0;
714            #if (-r "/etc/portage/package.keywords") {
715            #open(KEYW,"/etc/portage/package.keywords");
716            #while (<KEYW>) {
717            #$found = 1 if (/portage\/pb/);
718            #}
719            #close(KEYW);
720            #}
721            #if ($found == 0) {
722            #pb_system("sudo sh -c \"echo portage/pb >> /etc/portage/package.keywords\"");
723            #}
724
725            # Build
726            foreach my $f (@ebuildfile) {
727                if ($f =~ /\.ebuild$/) {
728                    move($f,"$tmpd/$pbpkg-$pbver.ebuild");
729                    pb_system("cd $tmpd ; ebuild $pbpkg-$pbver.ebuild clean ; ebuild $pbpkg-$pbver.ebuild digest ; ebuild $pbpkg-$pbver.ebuild package");
730                    # Now move it where pb expects it
731                    pb_mkdir_p("$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
732                    move("$tmpd/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
733                }
734            }
735
736            $made="$made portage/pb/sys-apps/$pbpkg/$pbpkg-$pbver.ebuild";
737        } elsif ($dtype eq "slackware") {
738            $made="$made build-$pbpkg/$pbpkg-$pbver-*-$pbtag.tgz";
739            pb_mkdir_p("$ENV{'PBBUILDDIR'}/install") if (! -d "$ENV{'PBBUILDDIR'}/install");
740        } else {
741            die "Unknown dtype format $dtype";
742        }
743    }
744    # Keep track of what is generated so that we can get them back from VMs
745    open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to create $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
746    print KEEP "$made\n";
747    close(KEEP);
748}
749
750sub pb_build2ssh {
751    pb_send2target("Sources");
752}
753
754sub pb_pkg2ssh {
755    pb_send2target("Packages");
756}
757
758# By default deliver to the the public site hosting the
759# ftp structure (or whatever) or a VM/VE
760sub pb_send2target {
761
762    my $cmt = shift;
763    my $v = shift || undef;
764    my $vmexist = shift || 0;           # 0 is FALSE
765    my $vmpid = shift || 0;             # 0 is FALSE
766
767    my $host = "sshhost";
768    my $login = "sshlogin";
769    my $dir = "sshdir";
770    my $port = "sshport";
771    my $tmout = "sshtmout";
772    my $path = "sshpath";
773    my $conf = "sshconf";
774    my $rebuild = "sshrebuild";
775    if ($cmt eq "vm") {
776        $login = "vmlogin";
777        $dir = "pbdefdir";
778        $tmout = "vmtmout";
779        $rebuild = "vmrebuild";
780        # Specific VM
781        $host = "vmhost";
782        $port = "vmport";
783    } elsif ($cmt eq "ve") {
784        $login = "velogin";
785        $dir = "pbdefdir";
786        $tmout = "vetmout";
787        # Specific VE
788        $path = "vepath";
789        $conf = "veconf";
790        $rebuild = "verebuild";
791    }
792    my $cmd = "";
793
794    # Get list of packages to build
795    my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
796    @pkgs = @$ptr;
797
798    # Get the running distro to consider
799    my ($odir,$over,$oarch) = (undef, undef);
800    if (defined $v) {
801        ($odir,$over,$oarch) = split(/-/,$v);
802    }
803    my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($odir,$over);
804    pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n");
805
806    # Get content saved in cms2build
807    my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
808    $pkg = { } if (not defined $pkg);
809
810    my $src = "";
811    chdir "$ENV{'PBBUILDDIR'}";
812    foreach my $pbpkg (@pkgs) {
813        my $vertag = $pkg->{$pbpkg};
814        # get the version of the current package - maybe different
815        ($pbver,$pbtag) = split(/-/,$vertag);
816
817        if (($cmt eq "Sources") || ($cmt eq "vm") || ($cmt eq "ve")) {
818            $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz";
819            if ($cmd eq "") {
820                $cmd = "ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz";
821            } else {
822                $cmd = "$cmd ; ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz";
823            }
824        }
825    }
826    if (($cmt eq "vm") || ($cmt eq "ve")) {
827        $src="$src $ENV{'PBDESTDIR'}/pbscript $ENV{'PBROOT'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb $ENV{'PBETC'}";
828    } elsif ($cmt eq "Script") {
829        $src="$src $ENV{'PBDESTDIR'}/pbscript";
830    } elsif ($cmt eq "Packages") {
831        # Get package list from file made during build2pkg
832        open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
833        $src = <KEEP>;
834        chomp($src);
835        close(KEEP);
836        if ($dtype eq "rpm") {
837            # Also make a pbscript to generate yum/urpmi bases
838            # $src = "$src $ENV{'PBDESTDIR'}/pbscript"
839        } elsif ($dtype eq "deb") {
840            # Also make a pbscript to generate apt bases
841            # $src = "$src $ENV{'PBDESTDIR'}/pbscript"
842        }
843    }
844    # Remove potential leading spaces (cause problem with basename)
845    $src =~ s/^ *//;
846    my $basesrc = "";
847    foreach my $i (split(/ +/,$src)) {
848        $basesrc .= " ".basename($i);
849    }
850
851    pb_log(0,"Sources handled ($cmt): $src\n");
852    my ($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf) = pb_conf_get($host,$login,$dir,$port,$tmout,$rebuild,$path,$conf);
853    pb_log(2,"ssh: ".Dumper(($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf))."\n");
854    # Not mandatory
855    my ($testver) = pb_conf_get_if("testver");
856
857    my $mac;
858    # Useless for VE
859    if ($cmt ne "ve") {
860        $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$sshhost->{$ENV{'PBPROJ'}}";
861        # Overwrite account value if passed as parameter
862        $mac = "$pbaccount\@$sshhost->{$ENV{'PBPROJ'}}" if (defined $pbaccount);
863    }
864
865    my $tdir;
866    my $bdir;
867    if (($cmt eq "Sources") || ($cmt eq "Script")) {
868        $tdir = "$sshdir->{$ENV{'PBPROJ'}}/src";
869    } elsif (($cmt eq "vm") || ($cmt eq "ve")) {
870        $tdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/delivery";
871        $bdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/build";
872        # Remove a potential $ENV{'HOME'} as bdir should be relative to pb's home
873        $bdir =~ s|\$ENV.+\}/||;
874    } elsif ($cmt eq "Packages") {
875        $tdir = "$sshdir->{$ENV{'PBPROJ'}}/$ddir/$dver";
876        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} eq "true")) {
877            # This is a test pkg => target dir is under test
878            $tdir .= "/test";
879        }
880    } else {
881        return;
882    }
883
884    # Useless for VE
885    my $nport;
886    if ($cmt ne "ve") {
887        $nport = $sshport->{$ENV{'PBPROJ'}};
888        $nport = "$pbport" if (defined $pbport);
889    }
890
891    # Remove a potential $ENV{'HOME'} as tdir should be relative to pb's home
892    $tdir =~ s|\$ENV.+\}/||;
893
894    my $tm = $vtmout->{$ENV{'PBPROJ'}};
895
896    # ssh communication if not VE
897    my ($shcmd,$cpcmd,$cptarget,$cp2target);
898    if ($cmt ne "ve") {
899        $shcmd = "ssh -q -p $nport $mac";
900        $cpcmd = "scp -p -P $nport";
901        $cptarget = "$mac:$tdir";
902        $cp2target = "$mac:$bdir";
903    } else {
904        my $tp = $vepath->{$ENV{'PBPROJ'}};
905        $shcmd = "sudo chroot $tp/$v /bin/su - $sshlogin->{$ENV{'PBPROJ'}} -c ";
906        $cpcmd = "cp -a ";
907        $cptarget = "$tp/$tdir";
908        $cp2target = "$tp/$bdir";
909    }
910
911    pb_system("$shcmd \"mkdir -p $tdir ; cd $tdir ; echo \'for i in $basesrc; do if [ -f \$i ]; then rm -f \$i; fi; done\ ; $cmd' | bash\"","Preparing $tdir on $cptarget");
912    pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget");
913    # For VE we need to change the owner manually - To be tested if needed
914    #if ($cmt eq "ve") {
915    #pb_system("cd $cptarget ; sudo chown -R $sshlogin->{$ENV{'PBPROJ'}} .","$cmt chown in $cptarget to $sshlogin->{$ENV{'PBPROJ'}}");
916    #}
917    pb_system("$shcmd \"echo \'cd $tdir ; if [ -f pbscript ]; then ./pbscript; fi\' | bash\"","Executing pbscript on $cptarget if needed");
918    if (($cmt eq "vm") || ($cmt eq "ve")) {
919        # Get back info on pkg produced, compute their name and get them from the VM
920        pb_system("$cpcmd $cp2target/pbgen-$pbprojver-$pbprojtag $ENV{'PBBUILDDIR'} 2> /dev/null","Get package names in $cp2target");
921        open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
922        my $src = <KEEP>;
923        chomp($src);
924        close(KEEP);
925        $src =~ s/^ *//;
926        pb_mkdir_p("$ENV{'PBBUILDDIR'}/$odir/$over");
927        # Change pgben to make the next send2target happy
928        my $made = "";
929        open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to write $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
930        foreach my $p (split(/ +/,$src)) {
931            my $j = basename($p);
932            pb_system("$cpcmd $cp2target/\'$p\' $ENV{'PBBUILDDIR'}/$odir/$over 2> /dev/null","Package recovery of $j in $cp2target");
933            $made="$made $odir/$over/$j" if (($dtype ne "rpm") || ($j !~ /.src.rpm$/));
934        }
935        print KEEP "$made\n";
936        close(KEEP);
937        pb_system("$shcmd \"rm -rf $tdir $bdir\"","$cmt cleanup");
938        pb_send2target("Packages","$odir"."_"."$over");
939        if ((! $vmexist) && ($cmt eq "vm")) {
940            pb_system("$shcmd \"sudo /sbin/halt -p \"; sleep $tm ; echo \'if [ -d /proc/$vmpid ]; then kill -9 $vmpid; fi \' | bash ; sleep 10","VM $v halt (pid $vmpid)");
941        }
942        pb_rm_rf("$ENV{'PBBUILDDIR'}/$odir");
943    }
944}
945
946sub pb_script2v {
947    my $pbscript=shift;
948    my $vtype=shift;
949
950    # Prepare the script to be executed on the VM
951    # in $ENV{'PBDESTDIR'}/pbscript
952    if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript")) {
953        copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
954        chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
955    }
956
957    my ($vm,$all) = pb_get_v($vtype);
958    my ($vmexist,$vmpid) = (undef,undef);
959
960    foreach my $v (@$vm) {
961        # Launch the VM/VE
962        if ($vtype eq "vm") {
963            ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
964
965            # Skip that VM if something went wrong
966            next if (($vmpid == 0) && ($vmexist ==0));
967        }
968
969        # Gather all required files to send them to the VM
970        # and launch the build through pbscript
971        pb_send2target("Script","$v",$vmexist,$vmpid);
972
973    }
974}
975
976sub pb_launchv {
977    my $vtype = shift;
978    my $v = shift;
979    my $create = shift || 0;        # By default do not create a VM
980
981    die "No VM/VE defined, unable to launch" if (not defined $v);
982    # Keep only the first VM in case many were given
983    $v =~ s/,.*//;
984
985    # Which is our local arch ? (standardize on i386 for those platforms)
986    my $arch = `uname -m`;
987    chomp($arch);
988    $arch =~ s/i.86/i386/;
989
990    # Launch the VMs/VEs
991    if ($vtype eq "vm") {
992        die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0));
993
994        my ($ptr,$vmopt,$vmport,$vmpath,$vmtmout,$vmsize) = pb_conf_get("vmtype","vmopt","vmport","vmpath","vmtmout","vmsize");
995
996        my $vmtype = $ptr->{$ENV{'PBPROJ'}};
997        if (not defined $ENV{'PBVMOPT'}) {
998            $ENV{'PBVMOPT'} = "";
999        }
1000        if (defined $vmopt->{$ENV{'PBPROJ'}}) {
1001            $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/);
1002        }
1003        my $nport = $vmport->{$ENV{'PBPROJ'}};
1004        $nport = "$pbport" if (defined $pbport);
1005   
1006        my $cmd;
1007        my $vmcmd;      # has to be used for pb_check_ps
1008        my $vmm;        # has to be used for pb_check_ps
1009        if ($vmtype eq "qemu") {
1010            my $qemucmd32;
1011            my $qemucmd64;
1012            if ($arch eq "x86_64") {
1013                $qemucmd32 = "/usr/bin/qemu-system-i386";
1014                $qemucmd64 = "/usr/bin/qemu";
1015            } else {
1016                $qemucmd32 = "/usr/bin/qemu";
1017                $qemucmd64 = "/usr/bin/qemu-system-x86_64";
1018            }
1019        if ($v =~ /x86_64/) {
1020                $vmcmd = "$qemucmd64 -no-kqemu";
1021            } else {
1022                $vmcmd = "$qemucmd32";
1023            }
1024            $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu";
1025            if ($create != 0) {
1026                $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d";
1027            }
1028            $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm"
1029        } elsif ($vmtype eq "xen") {
1030        } elsif ($vmtype eq "vmware") {
1031        } else {
1032            die "VM of type $vmtype not supported. Report to the dev team";
1033        }
1034        my ($tmpcmd,$void) = split(/ +/,$cmd);
1035        my $vmexist = pb_check_ps($tmpcmd,$vmm);
1036        my $vmpid = 0;
1037        if (! $vmexist) {
1038            if ($create != 0) {
1039                if (($vmtype eq "qemu") || ($vmtype eq "xen")) {
1040                    pb_system("/usr/bin/qemu-img create -f qcow2 $vmm $vmsize->{$ENV{'PBPROJ'}}","Creating the QEMU VM");
1041                } elsif ($vmtype eq "vmware") {
1042                } else {
1043                }
1044            }
1045            if (! -f "$vmm") {
1046                pb_log(0,"Unable to find VM $vmm\n");
1047            } else {
1048                pb_system("$cmd &","Launching the VM $vmm");
1049                pb_system("sleep $vmtmout->{$ENV{'PBPROJ'}}","Waiting for VM $v to come up");
1050                $vmpid = pb_check_ps($tmpcmd,$vmm);
1051            }
1052        } else {
1053            pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n");
1054        }
1055        return($vmexist,$vmpid);
1056    # VE here
1057    } else {
1058        # Get VE context
1059        my ($ptr,$vepath,$vetmout,$verebuild,$veconf) = pb_conf_get("vetype","vepath","vetmout","verebuild","veconf");
1060        my $vetype = $ptr->{$ENV{'PBPROJ'}};
1061
1062        # Get distro context
1063        my ($name,$ver,$darch) = split(/-/,$v);
1064        chomp($darch);
1065        my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver);
1066
1067        if ($vetype eq "chroot") {
1068            # Architecture consistency
1069            if ($arch ne $darch) {
1070                die "Unable to launch a VE of architecture $darch on a $arch platform" if (not (($darch eq "x86_64") && ($arch =~ /i?86/)));
1071            }
1072
1073            if (($create != 0) || ($verebuild->{$ENV{'PBPROJ'}} eq "true") || ($force == 1)) {
1074                # We have to rebuild the chroot
1075                if ($dtype eq "rpm") {
1076                    pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1077                    # Once setup we need to install some packages, the pb account, ...
1078                    pb_system("sudo /usr/sbin/mock --install --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v su","Configuring the mock VE");
1079                    #pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" --basedir=\"$vepath->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1080                } elsif ($dtype eq "deb") {
1081                    pb_system("","Creating the pbuilder VE");
1082                } elsif ($dtype eq "ebuild") {
1083                    die "Please teach the dev team how to build gentoo chroot";
1084                } else {
1085                    die "Unknown distribution type $dtype. Report to dev team";
1086                }
1087            }
1088            # Nothing more to do for VE. No real launch
1089        } else {
1090            die "VE of type $vetype not supported. Report to the dev team";
1091        }
1092    }
1093}
1094
1095sub pb_build2v {
1096
1097my $vtype = shift;
1098
1099# Prepare the script to be executed on the VM/VE
1100# in $ENV{'PBDESTDIR'}/pbscript
1101my ($ntp) = pb_conf_get($vtype."ntp");
1102my $vntp = $ntp->{$ENV{'PBPROJ'}};
1103
1104open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
1105print SCRIPT "#!/bin/bash\n";
1106print SCRIPT "echo ... Execution needed\n";
1107print SCRIPT "# This is in directory delivery\n";
1108print SCRIPT "# Setup the variables required for building\n";
1109print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n";
1110print SCRIPT "# Preparation for pb\n";
1111print SCRIPT "mv .pbrc \$HOME\n";
1112print SCRIPT "cd ..\n";
1113# Force new date to be in the future compared to the date of the tar file by adding 1 minute
1114my @date=pb_get_date();
1115$date[1]++;
1116my $upddate = strftime("%m%d%H%M%Y", @date);
1117print SCRIPT "echo Setting up date on $vntp...\n";
1118# Or use ntpdate if available TBC
1119print SCRIPT "sudo date $upddate\n";
1120# This exports avoids pb_env_init to deal with PBCONF stuff
1121print SCRIPT "export PBCONF=/tmp\n";
1122print SCRIPT "export PBVER=$ENV{'PBVER'}\n";
1123print SCRIPT "export PBTAG=$ENV{'PBTAG'}\n";
1124print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n";
1125print SCRIPT "# Build\n";
1126# Get list of packages to build
1127my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
1128@pkgs = @$ptr;
1129my $p = join(' ',@pkgs) if (@pkgs);
1130print SCRIPT "echo Building packages on $vtype...\n";
1131print SCRIPT "pb -p $ENV{'PBPROJ'} build2pkg $p\n";
1132close(SCRIPT);
1133chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
1134
1135my ($v,$all) = pb_get_v($vtype);
1136
1137# Send tar files when we do a global generation
1138pb_build2ssh() if ($all == 1);
1139
1140my ($vmexist,$vmpid) = (undef,undef);
1141
1142foreach my $v (@$v) {
1143    if ($vtype eq "vm") {
1144        # Launch the VM
1145        my ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
1146
1147        # Skip that VM if it something went wrong
1148        next if (($vmpid == 0) && ($vmexist == 0));
1149    }
1150    # Gather all required files to send them to the VM/VE
1151    # and launch the build thourgh pbscript
1152    pb_send2target($vtype,"$v",$vmexist,$vmpid);
1153}
1154}
1155
1156
1157sub pb_newver {
1158
1159    die "-V Version parameter needed" if ((not defined $newver) || ($newver eq ""));
1160    my $scheme=pb_cms_init($ENV{'PBPROJ'});
1161    if ($scheme ne "svn") {
1162        die "Only SVN is supported at the moment";
1163    }
1164    my $res = pb_cms_isdiff($scheme);
1165    die "You need to have no differences before creating a new version" if ($res != 0);
1166    my $cmsurl = pb_cms_get_uri($scheme,$ENV{'PBROOT'});
1167    my $newurl = dirname($cmsurl)."/$newver";
1168    pb_cms_copy($scheme,$cmsurl,$newurl);
1169    pb_cms_checkout($scheme,$newurl,"$ENV{'PBROOT'}/../$newver");
1170    my $oldver=basename($cmsurl);
1171    open(FILE,"$ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb";
1172    open(OUT,"> $ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new";
1173    while(<FILE>) {
1174        s/projver\s+$ENV{'PBPROJ'}\s*=\s*$oldver/projver $ENV{'PBPROJ'} = $newver/;
1175        print OUT $_;
1176    }
1177    close(FILE);
1178    close(OUT);
1179    rename("$ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new","$ENV{'PBROOT'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb");
1180    pb_cms_checkin($scheme,"$ENV{'PBROOT'}/../$newver");
1181}
1182
1183#
1184# Return the list of VMs/VEs we are working on
1185# $all is a flag to know if we return all of them
1186# or only some (if all we publish also tar files in addition to pkgs
1187#
1188sub pb_get_v {
1189
1190my $vtype = shift;
1191my @v;
1192my $all = 0;
1193my $vlist;
1194my $pbv = 'PBV';
1195
1196if ($vtype eq "vm") {
1197    $vlist = "vmlist";
1198} elsif ($vtype eq "ve") {
1199    $vlist = "velist";
1200}
1201# Get VM/VE list
1202if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) {
1203    my ($ptr) = pb_conf_get($vlist);
1204    $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}};
1205    $all = 1;
1206}
1207pb_log(2,"$vtype: $ENV{$pbv}\n");
1208@v = split(/,/,$ENV{$pbv});
1209return(\@v,$all);
1210}
1211
1212sub pb_setup_v {
1213# Function to create a potentialy missing pb account on the VM/VE, and adds it to sudo
1214# Needs to use root account to connect to the VM/VE
1215
1216# pb will take your local public SSH key to access
1217# the pb account in the VM later on
1218
1219my $vtype = shift;
1220
1221my $file = "$ENV{'HOME'}/.ssh/id_dsa.pub";
1222die "Unable to find your public ssh key as $file";
1223
1224open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
1225print SCRIPT << 'EOF';
1226#!/usr/bin/perl -w
1227
1228$file="/etc/passwd";
1229open(PBFILE,$file) || die "Unable to open $file";
1230my $found = 0;
1231while (<PBFILE>) {
1232    $found = 1 if (/^pb:/);
1233}
1234close(PBFILE);
1235
1236if ( $found == 0 ) {
1237    if ( ! -d "/home" ) {
1238        mkdir "/home";
1239    }
1240    system "groupadd pb";
1241    system "useradd pb -g pb -m -d /home/pb";
1242}
1243
1244# For root
1245mkdir ".ssh",0700;
1246system 'cp /tmp/pbkey .ssh/authorized_keys';
1247chmod 0600,".ssh/authorized_keys";
1248
1249# For pb
1250chdir "/home/pb";
1251mkdir ".ssh",0700;
1252system 'cp /tmp/pbkey .ssh/authorized_keys';
1253chmod 0600,".ssh/authorized_keys";
1254system 'chown -R pb:pb .ssh';
1255
1256# No passwd for pb only keys
1257$file="/etc/shadow";
1258open(PBFILE,$file) || die "Unable to open $file";
1259open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1260while (<PBFILE>) {
1261    s/^pb:\!\!:/pb:*:/;
1262    s/^pb:\!:/pb:*:/;   #SLES 9 e.g.
1263    print PBOUT $_;
1264}
1265close(PBFILE);
1266close(PBOUT);
1267rename("$file.new",$file);
1268chmod 0640,$file;
1269
1270# pb has to be added to portage group on gentoo
1271unlink "/tmp/pbkey";
1272
1273my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init(); 
1274print "distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n";
1275
1276# Get and install pb
1277if ( $ddir eq "fedora" ) {
1278    system "yum clean all";
1279    system "yum update -y";
1280    my $arch=`uname -m`;
1281    my $opt = "";
1282    chomp($arch);
1283    if ($arch eq "x86_64") {
1284        $opt="--exclude=*.i?86";
1285    }
1286
1287    system "yum -y $opt install rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker";
1288} elsif (( $dfam eq "rh" ) || ($ddir eq "sles") || (($ddir eq "suse") && (($dver eq "10.1") || ($dver eq "10.0"))) || (($ddir eq "mandrake") && ($dver eq "10.1"))) {
1289    # Suppose pkg are installed already
1290    system "rpm -e lsb 2>&1 > /dev/null";
1291    system "rm -rf DateManip* ; wget http://search.cpan.org/CPAN/authors/id/S/SB/SBECK/Date-Manip-5.46.tar.gz ; tar xvfz Date-Manip-5.46.tar.gz ; cd Date-Manip* ; perl Makefile.PL ; make ; make install ; cd .. ";
1292} elsif ($ddir eq "suse") { 
1293    # New OpenSuSE
1294    system "export TERM=linux ; liste=\"\" ; for i in make wget patch sudo perl-DateManip perl-File-HomeDir xntp; do rpm -q \$i 1> /dev/null 2> /dev/null ; if [ \$\? != 0 ]; then liste=\"\$liste \$i\"; fi; done; echo \"Liste: \$liste\" ; if [ \"\$liste\" != \"\" ]; then yast2 -i \$liste ; fi";
1295} elsif ( $dfam eq "md" ) {
1296        system "urpmi.update -a ; urpmi --auto rpm-build wget sudo patch ntp-client perl-DateManip";
1297} elsif ( $dfam eq "du" ) {
1298    if (( $dver eq "3.1" ) && ($ddir eq "debian")) {
1299        system "apt-get update; apt-get -y install wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libdate-manip-perl";
1300    } else  {
1301        system "apt-get update; apt-get -y install wget patch openssh-server dpkg-dev sudo debian-builder dh-make fakeroot ntpdate rses5-dev libdate-manip-perl";
1302    }
1303} elsif ( $dfam eq "gen" ) {
1304        system "emerge -u system ; emerge wget sudo ntp DateManip";
1305} else {
1306    print "No pkg to install\n";
1307}
1308
1309# Adapt sudoers
1310$file="/etc/sudoers";
1311open(PBFILE,$file) || die "Unable to open $file";
1312open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1313while (<PBFILE>) {
1314    next if (/^pb   /);
1315    s/Defaults[ \t]+requiretty//;
1316    print PBOUT $_;
1317}
1318close(PBFILE);
1319print PBOUT "pb   ALL=(ALL) NOPASSWD:ALL\n";
1320close(PBOUT);
1321rename("$file.new",$file);
1322chmod 0440,$file;
1323
1324# Suse wants sudoers as 640
1325if (($ddir eq "sles") || (($ddir eq "suse")) && ($dver ne "10.3")) {
1326    chmod 0640,$file;
1327}
1328
1329# Sync date
1330system "/usr/sbin/ntpdate ntp.pool.org";
1331
1332system "rm -rf project-builder-* ; wget --passive-ftp ftp://ftp.mondorescue.org/src/project-builder-latest.tar.gz ; tar xvfz project-builder-latest.tar.gz ; cd project-builder-* ; perl Makefile.PL ; make ; make install ; cd ..";
1333EOF
1334close(SCRIPT);
1335}
1336
1337# Returns the pid of a running VM command using a specific VM file
1338sub pb_check_ps {
1339    my $vmcmd = shift;
1340    my $vmm = shift;
1341    my $vmexist = 0;        # FALSE by default
1342
1343    open(PS, "ps auxhww|") || die "Unable to call ps";
1344    while (<PS>) {
1345        next if (! /$vmcmd/);
1346        next if (! /$vmm/);
1347        my ($void1, $void2);
1348        ($void1, $vmexist, $void2) = split(/ +/);
1349        last;
1350    }
1351    return($vmexist);
1352}
1353
1354
1355sub pb_extract_build_files {
1356
1357my $src=shift;
1358my $dir=shift;
1359my $ddir=shift;
1360my @files;
1361
1362if ($src =~ /tar\.gz$/) {
1363    pb_system("tar xfpz $src $dir","Extracting build files");
1364} elsif ($src =~ /tar\.bz2$/) {
1365    pb_system("tar xfpj $src $dir","Extracting build files");
1366} else {
1367    die "Unknown compression algorithm for $src";
1368}
1369opendir(DIR,"$dir") || die "Unable to open directory $dir";
1370foreach my $f (readdir(DIR)) {
1371    next if ($f =~ /^\./);
1372    move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
1373    pb_log(2,"mv $dir/$f $ddir\n");
1374    push @files,"$ddir/$f";
1375}
1376closedir(DIR);
1377# Not enough but still a first cleanup
1378pb_rm_rf("$dir");
1379return(@files);
1380}
1381
1382sub pb_list_bfiles {
1383
1384my $dir = shift;
1385my $pbpkg = shift;
1386my $bfiles = shift;
1387my $pkgfiles = shift;
1388my $supfiles = shift;
1389
1390opendir(BDIR,"$dir") || die "Unable to open dir $dir: $!";
1391foreach my $f (readdir(BDIR)) {
1392    next if ($f =~ /^\./);
1393    $bfiles->{$f} = "$dir/$f";
1394    $bfiles->{$f} =~ s~$ENV{'PBROOT'}~~;
1395    if (defined $supfiles->{$pbpkg}) {
1396        $pkgfiles->{$f} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/);
1397    }
1398}
1399closedir(BDIR);
1400}
1401
1402
1403sub pb_syntax {
1404
1405my $exit_status = shift || -1;
1406my $verbose_level = shift || 0;
1407
1408my $filehandle = \*STDERR;
1409
1410$filehandle = \*STDOUT if ($exit_status == 0);
1411
1412pod2usage( { -message => "pb (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n",
1413             -exitval => $exit_status  ,
1414             -verbose => $verbose_level,
1415             -output  => $filehandle } );
1416}
1417
1418
Note: See TracBrowser for help on using the repository browser.