source: devel/pb/bin/pb @ 347

Last change on this file since 347 was 347, checked in by Bruno Cornec, 12 years ago

setupvm seems better now

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