source: devel/pb/bin/pb @ 351

Revision 351, 47.1 KB checked in by bruno, 5 years ago (diff)

Attempt to have better slackware support for setupvm

  • Property svn:executable set to *
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        # That buil script needs to be run as root
436        $pbaccount = "root";
437        pb_script2v($pbscript,"ve");
438} elsif ($action =~ /^setupvm$/) {
439        my $pbscript = pb_setup_v("vm");
440        # That buil script needs to be run as root
441        $pbaccount = "root";
442        pb_script2v($pbscript,"vm");
443} elsif ($action =~ /^newproj$/) {
444        # Nothing to do - already done in pb_env_init
445} elsif ($action =~ /^clean$/) {
446} else {
447        pb_log(0,"\'$action\' is not available\n");
448        pb_syntax(-2,1);
449}
450
451sub pb_cms2build {
452
453        my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
454        @pkgs = @$ptr;
455
456        my ($scheme, $uri) = pb_cms_init($pbinit);
457
458        my ($pkgv, $pkgt) = pb_conf_get_if("pkgver","pkgtag");
459
460        # declare packager for filtering
461        my ($tmp) = pb_conf_get("pbpackager");
462        my $pbpackager = $tmp->{$ENV{'PBPROJ'}};
463
464        foreach my $pbpkg (@pkgs) {
465                $ENV{'PBPKG'} = $pbpkg;
466                $ENV{'PBVER'} = $pbprojver;
467                $ENV{'PBTAG'} = $pbprojtag;
468                if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) {
469                        $pbver = $pkgv->{$pbpkg};
470                        $ENV{'PBVER'} = $pbver;
471                } else {
472                        $pbver = $ENV{'PBVER'};
473                }
474                if ((defined $pkgt) && (defined $pkgt->{$pbpkg})) {
475                        $pbtag = $pkgt->{$pbpkg};
476                        $ENV{'PBTAG'} = $pbtag;
477                } else {
478                        $pbtag = $ENV{'PBTAG'};
479                }
480
481                $pbrev = $ENV{'PBREVISION'};
482                pb_log(0,"\n");
483                pb_log(0,"Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n");
484                die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
485                # Clean up dest if necessary. The export will recreate it
486                my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver";
487                pb_rm_rf($dest) if (-d $dest);
488
489                # Export CMS tree for the concerned package to dest
490                # And generate some additional files
491                $OUTPUT_AUTOFLUSH=1;
492
493                # computes in which dir we have to work
494                my $dir = $defpkgdir->{$pbpkg};
495                $dir = $extpkgdir->{$pbpkg} if (not defined $dir);
496                pb_log(2,"def:".Dumper($defpkgdir)." ext: ".Dumper($extpkgdir)." \n");
497
498                # Exporting from CMS
499                pb_cms_export($uri,"$ENV{'PBDIR'}/$dir",$dest);
500
501                # Get project info on authors and log file
502                my $chglog = "$ENV{'PBROOTDIR'}/$pbpkg/pbcl";
503                $chglog = "$ENV{'PBROOTDIR'}/pbcl" if (! -f $chglog);
504                $chglog = undef if (! -f $chglog);
505
506                my $authors = "$ENV{'PBROOTDIR'}/$pbpkg/pbauthors";
507                $authors = "$ENV{'PBROOTDIR'}/pbauthors" if (! -f $authors);
508                $authors = "/dev/null" if (! -f $authors);
509
510                # Extract cms log history and store it
511                if ((defined $chglog) && (! -f "$dest/NEWS")) {
512                        pb_log(2,"Generating NEWS file from $chglog\n");
513                        copy($chglog,"$dest/NEWS") || die "Unable to create $dest/NEWS";
514                }
515                pb_cms_log($scheme,"$ENV{'PBDIR'}/$dir",$dest,$chglog,$authors);
516
517                my %build;
518
519                my @pt;
520                @pt = pb_conf_get_if("vmlist","velist");
521                my $tmpl = "";
522                if (defined $pt[0]->{$ENV{'PBPROJ'}}) {
523                        $tmpl .= $pt[0]->{$ENV{'PBPROJ'}};
524                }
525                if (defined $pt[1]->{$ENV{'PBPROJ'}}) {
526                        # the 2 lists needs to be grouped with a ',' separated them
527                        if ($tmpl ne "") {
528                                $tmpl .= ",";
529                        }
530                        $tmpl .= $pt[1]->{$ENV{'PBPROJ'}} 
531                }
532                foreach my $d (split(/,/,$tmpl)) {
533                        my ($name,$ver,$arch) = split(/-/,$d);
534                        chomp($arch);
535                        my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver);
536                        pb_log(2,"DEBUG: distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf)."\n");
537                        pb_log(2,"DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n");
538
539                        # Filter build files from the less precise up to the most with overloading
540                        # Filter all files found, keeping the name, and generating in dest
541
542                        # Find all build files first relatively to PBROOTDIR
543                        # Find also all specific files referenced in the .pb conf file
544                        my %bfiles = ();
545                        my %pkgfiles = ();
546                        $build{"$ddir-$dver"} = "yes";
547
548                        if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$dtype") {
549                                pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$dtype",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
550                        } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$dfam") {
551                                pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$dfam",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
552                        } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$ddir") {
553                                pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$ddir",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
554                        } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$ddir-$dver") {
555                                pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$ddir-$dver",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
556                        } else {
557                                $build{"$ddir-$dver"} = "no";
558                                next;
559                        }
560                        pb_log(2,"DEBUG bfiles: ".Dumper(\%bfiles)."\n");
561
562                        # Get all filters to apply
563                        my $ptr = pb_get_filters($pbpkg, $dtype, $dfam, $ddir, $dver);
564
565                        # Apply now all the filters on all the files concerned
566                        # destination dir depends on the type of file
567                        if (defined $ptr) {
568                                foreach my $f (values %bfiles,values %pkgfiles) {
569                                        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);
570                                }
571                        }
572                }
573                my @found;
574                my @notfound;
575                foreach my $b (keys %build) {
576                        push @found,$b if ($build{$b} =~ /yes/);
577                        push @notfound,$b if ($build{$b} =~ /no/);
578                }
579                pb_log(0,"Build files generated for ".join(',',@found)."\n");
580                pb_log(0,"No Build files found for ".join(',',@notfound)."\n") if (@notfound);
581                # Get the generic filter (all.pbf) and
582                # apply those to the non-build files including those
583                # generated by pbinit if applicable
584
585                # Get only all.pbf filter
586                $ptr = pb_get_filters($pbpkg);
587
588                my $liste ="";
589                if (defined $filteredfiles->{$pbpkg}) {
590                        foreach my $f (split(/,/,$filteredfiles->{$pbpkg})) {
591                                pb_filter_file_inplace($ptr,"$dest/$f",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$pbpackager);
592                                $liste = "$f $liste";
593                        }
594                }
595                pb_log(2,"Files ".$liste."have been filtered\n");
596
597                # Prepare the dest directory for archive
598                if (-x "$ENV{'PBROOTDIR'}/$pbpkg/pbinit") {
599                        pb_filter_file("$ENV{'PBROOTDIR'}/$pbpkg/pbinit",$ptr,"$ENV{'PBTMP'}/pbinit",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$pbpackager);
600                        chmod 0755,"$ENV{'PBTMP'}/pbinit";
601                        pb_system("cd $dest ; $ENV{'PBTMP'}/pbinit","Executing init script from $ENV{'PBROOTDIR'}/$pbpkg/pbinit");
602                }
603
604                # Archive dest dir
605                chdir "$ENV{'PBDESTDIR'}" || die "Unable to change dir to $ENV{'PBDESTDIR'}";
606                # Possibility to look at PBSRC to guess more the filename
607                pb_system("tar cfz $pbpkg-$pbver.tar.gz $pbpkg-$pbver","Creating $pbpkg tar files compressed");
608                pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz\n");
609
610                # Keep track of what is generated by default
611                open(LAST,"> $ENV{'PBDESTDIR'}/pbrc") || die "Unable to create $ENV{'PBDESTDIR'}/pbrc";
612                #print LAST "pbroot $pbprojver-$pbprojtag = $ENV{'PBROOTDIR'}\n";
613                # Why not use pbproj ?
614                print LAST "pbroot $ENV{'PBPROJ'} = $ENV{'PBROOTDIR'}\n";
615                close(LAST);
616
617                # Keep track of per package version
618                my ($pkg) = pb_conf_read_if("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
619                $pkg = { } if (not defined $pkg);
620                if ((not defined $pkg->{$pbpkg}) || ($pkg->{$pbpkg} ne "$pbver-$pbtag")) {
621                        $pkg->{$pbpkg} = "$pbver-$pbtag";
622                }
623
624                pb_log(2,"DEBUG pkg: ".Dumper($pkg)."\n");
625                open(PKG,"> $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb") || die "Unable to create $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb";
626                foreach my $p (keys %$pkg) {
627                        print PKG "pbpkg $p = $pkg->{$p}\n";
628                }
629                close(PKG);
630
631                # Final cleanup
632                pb_rm_rf($dest) if (-d $dest);
633        }
634}
635
636sub pb_build2pkg {
637
638        # Get list of packages to build
639        my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
640        @pkgs = @$ptr;
641
642        # Get the running distro to build on
643        my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init();
644        pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n");
645
646        # Get content saved in cms2build
647        my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
648        $pkg = { } if (not defined $pkg);
649
650        # declare packager (via env var in VM/VE
651        my $pbpackager;
652        if (not defined $ENV{'PBPACKAGER'}) {
653                my ($tmp) = pb_conf_get("pbpackager");
654                $pbpackager = $tmp->{$ENV{'PBPROJ'}};
655        } else {
656                $pbpackager = $ENV{'PBPACKAGER'};
657        }
658
659        chdir "$ENV{'PBBUILDDIR'}";
660        my $made = ""; # pkgs made during build
661        foreach my $pbpkg (@pkgs) {
662                my $vertag = $pkg->{$pbpkg};
663                # get the version of the current package - maybe different
664                ($pbver,$pbtag) = split(/-/,$vertag);
665
666                my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz";
667                pb_log(2,"Source file: $src\n");
668
669                pb_log(2,"Working directory: $ENV{'PBBUILDDIR'}\n");
670                if ($dtype eq "rpm") {
671                        foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') {
672                                if (! -d "$ENV{'PBBUILDDIR'}/$d") {
673                                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";
674                                }
675                        }
676
677                        # Remove in case a previous link/file was there
678                        unlink "$ENV{'PBBUILDDIR'}/SOURCES/".basename($src);
679                        symlink "$src","$ENV{'PBBUILDDIR'}/SOURCES/".basename($src) || die "Unable to symlink $src in $ENV{'PBBUILDDIR'}/SOURCES";
680                        # We need to first extract the spec file
681                        my @specfile;
682                        @specfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$ENV{'PBBUILDDIR'}/SPECS");
683
684                        pb_log(2,"specfile: ".Dumper(\@specfile)."\n");
685                        # set LANGUAGE to check for correct log messages
686                        $ENV{'LANGUAGE'}="C";
687                        foreach my $f (@specfile) {
688                                if ($f =~ /\.spec$/) {
689                                        pb_system("rpmbuild --define \'packager $pbpackager\' --define \"_topdir $ENV{'PBBUILDDIR'}\" -ba $f","Building package with $f under $ENV{'PBBUILDDIR'}");
690                                        last;
691                                }
692                        }
693                        $made="$made RPMS/*/$pbpkg-$pbver-$pbtag$pbsuf.*.rpm SRPMS/$pbpkg-$pbver-$pbtag$pbsuf.src.rpm";
694                        if (-f "/usr/bin/rpmlint") {
695                                pb_system("rpmlint $made","Checking validity of rpms with rpmlint");
696                        }
697                } elsif ($dtype eq "deb") {
698                        chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
699                        pb_system("tar xfz $src","Extracting sources");
700
701                        chdir "$pbpkg-$pbver" || die "Unable to chdir to $pbpkg-$pbver";
702                        pb_rm_rf("debian");
703                        symlink "pbconf/$ddir-$dver","debian" || die "Unable to symlink to pbconf/$ddir-$dver";
704                        chmod 0755,"debian/rules";
705                        pb_system("dpkg-buildpackage -us -uc -rfakeroot","Building package");
706                        $made="$made $pbpkg"."_*.deb $pbpkg"."_*.dsc $pbpkg"."_*.tar.gz";
707                        if (-f "/usr/bin/lintian") {
708                                pb_system("lintian $made","Checking validity of debs with lintian");
709                        }
710                } elsif ($dtype eq "ebuild") {
711                        my @ebuildfile;
712                        # For gentoo we need to take pb as subsystem name
713                        # We put every apps here under sys-apps. hope it's correct
714                        # We use pb's home dir in order o have a single OVERLAY line
715                        my $tmpd = "$ENV{'HOME'}/portage/pb/sys-apps/$pbpkg";
716                        pb_mkdir_p($tmpd) if (! -d "$tmpd");
717                        pb_mkdir_p("$ENV{'HOME'}/portage/distfiles") if (! -d "$ENV{'HOME'}/portage/distfiles");
718
719                        # We need to first extract the ebuild file
720                        @ebuildfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$tmpd");
721
722                        # Prepare the build env for gentoo
723                        my $found = 0;
724                        my $pbbd = $ENV{'HOME'};
725                        $pbbd =~ s|/|\\/|g;
726                        if (-r "/etc/make.conf") {
727                                open(MAKE,"/etc/make.conf");
728                                while (<MAKE>) {
729                                        $found = 1 if (/$pbbd\/portage/);
730                                }
731                                close(MAKE);
732                        }
733                        if ($found == 0) {
734                                pb_system("sudo sh -c 'echo PORTDIR_OVERLAY=\"$ENV{'HOME'}/portage\" >> /etc/make.conf'");
735                        }
736                        #$found = 0;
737                        #if (-r "/etc/portage/package.keywords") {
738                        #open(KEYW,"/etc/portage/package.keywords");
739                        #while (<KEYW>) {
740                        #$found = 1 if (/portage\/pb/);
741                        #}
742                        #close(KEYW);
743                        #}
744                        #if ($found == 0) {
745                        #pb_system("sudo sh -c \"echo portage/pb >> /etc/portage/package.keywords\"");
746                        #}
747
748                        # Build
749                        foreach my $f (@ebuildfile) {
750                                if ($f =~ /\.ebuild$/) {
751                                        move($f,"$tmpd/$pbpkg-$pbver.ebuild");
752                                        pb_system("cd $tmpd ; ebuild $pbpkg-$pbver.ebuild clean ; ebuild $pbpkg-$pbver.ebuild digest ; ebuild $pbpkg-$pbver.ebuild package");
753                                        # Now move it where pb expects it
754                                        pb_mkdir_p("$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
755                                        move("$tmpd/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
756                                }
757                        }
758
759                        $made="$made portage/pb/sys-apps/$pbpkg/$pbpkg-$pbver.ebuild";
760                } elsif ($dtype eq "slackware") {
761                        $made="$made build-$pbpkg/$pbpkg-$pbver-*-$pbtag.tgz";
762                        pb_mkdir_p("$ENV{'PBBUILDDIR'}/install") if (! -d "$ENV{'PBBUILDDIR'}/install");
763                } else {
764                        die "Unknown dtype format $dtype";
765                }
766        }
767        # Keep track of what is generated so that we can get them back from VMs
768        open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to create $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
769        print KEEP "$made\n";
770        close(KEEP);
771}
772
773sub pb_build2ssh {
774        pb_send2target("Sources");
775}
776
777sub pb_pkg2ssh {
778        pb_send2target("Packages");
779}
780
781# By default deliver to the the public site hosting the
782# ftp structure (or whatever) or a VM/VE
783sub pb_send2target {
784
785        my $cmt = shift;
786        my $v = shift || undef;
787        my $vmexist = shift || 0;                       # 0 is FALSE
788        my $vmpid = shift || 0;                         # 0 is FALSE
789
790        my $host = "sshhost";
791        my $login = "sshlogin";
792        my $dir = "sshdir";
793        my $port = "sshport";
794        my $tmout = "sshtmout";
795        my $path = "sshpath";
796        my $conf = "sshconf";
797        my $rebuild = "sshrebuild";
798        if (($cmt eq "vm") || ($cmt eq "Script")) {
799                $login = "vmlogin";
800                $dir = "pbdefdir";
801                $tmout = "vmtmout";
802                $rebuild = "vmrebuild";
803                # Specific VM
804                $host = "vmhost";
805                $port = "vmport";
806        } elsif ($cmt eq "ve") {
807                $login = "velogin";
808                $dir = "pbdefdir";
809                $tmout = "vetmout";
810                # Specific VE
811                $path = "vepath";
812                $conf = "veconf";
813                $rebuild = "verebuild";
814        }
815        my $cmd = "";
816
817        # Get list of packages to build
818        my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
819        @pkgs = @$ptr;
820
821        # Get the running distro to consider
822        my ($odir,$over,$oarch) = (undef, undef, undef);
823        if (defined $v) {
824                ($odir,$over,$oarch) = split(/-/,$v);
825        }
826        my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($odir,$over);
827        pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n");
828
829        # Get content saved in cms2build
830        my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb","pbpkg");
831        $pkg = { } if (not defined $pkg);
832
833        my $src = "";
834        chdir "$ENV{'PBBUILDDIR'}";
835        foreach my $pbpkg (@pkgs) {
836                my $vertag = $pkg->{$pbpkg};
837                # get the version of the current package - maybe different
838                ($pbver,$pbtag) = split(/-/,$vertag);
839
840                if (($cmt eq "Sources") || ($cmt eq "vm") || ($cmt eq "ve")) {
841                        $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz";
842                        if ($cmd eq "") {
843                                $cmd = "ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz";
844                        } else {
845                                $cmd = "$cmd ; ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz";
846                        }
847                }
848        }
849        if (($cmt eq "vm") || ($cmt eq "ve")) {
850                $src="$src $ENV{'PBDESTDIR'}/pbscript $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$pbprojver-$pbprojtag.pb $ENV{'PBETC'}";
851        } elsif ($cmt eq "Script") {
852                $src="$src $ENV{'PBDESTDIR'}/pbscript";
853        } elsif ($cmt eq "Packages") {
854                # Get package list from file made during build2pkg
855                open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
856                $src = <KEEP>;
857                chomp($src);
858                close(KEEP);
859                if ($dtype eq "rpm") {
860                        # Also make a pbscript to generate yum/urpmi bases
861                        # $src = "$src $ENV{'PBDESTDIR'}/pbscript"
862                } elsif ($dtype eq "deb") {
863                        # Also make a pbscript to generate apt bases
864                        # $src = "$src $ENV{'PBDESTDIR'}/pbscript"
865                }
866        }
867        # Remove potential leading spaces (cause problem with basename)
868        $src =~ s/^ *//;
869        my $basesrc = "";
870        foreach my $i (split(/ +/,$src)) {
871                $basesrc .= " ".basename($i);
872        }
873
874        pb_log(0,"Sources handled ($cmt): $src\n");
875        my ($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf) = pb_conf_get($host,$login,$dir,$port,$tmout,$rebuild,$path,$conf);
876        pb_log(2,"ssh: ".Dumper(($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf))."\n");
877        # Not mandatory
878        my ($testver) = pb_conf_get_if("testver");
879
880        my $mac;
881        # Useless for VE
882        if ($cmt ne "ve") {
883                $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$sshhost->{$ENV{'PBPROJ'}}";
884                # Overwrite account value if passed as parameter
885                $mac = "$pbaccount\@$sshhost->{$ENV{'PBPROJ'}}" if (defined $pbaccount);
886        }
887
888        my $tdir;
889        my $bdir;
890        if (($cmt eq "Sources") || ($cmt eq "Script")) {
891                $tdir = "$sshdir->{$ENV{'PBPROJ'}}/src";
892        } elsif (($cmt eq "vm") || ($cmt eq "ve")) {
893                $tdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/delivery";
894                $bdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/build";
895                # Remove a potential $ENV{'HOME'} as bdir should be relative to pb's home
896                $bdir =~ s|\$ENV.+\}/||;
897        } elsif ($cmt eq "Packages") {
898                $tdir = "$sshdir->{$ENV{'PBPROJ'}}/$ddir/$dver";
899                if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
900                        # This is a test pkg => target dir is under test
901                        $tdir .= "/test";
902                }
903        } else {
904                return;
905        }
906
907        # Useless for VE
908        my $nport;
909        if ($cmt ne "ve") {
910                $nport = $sshport->{$ENV{'PBPROJ'}};
911                $nport = "$pbport" if (defined $pbport);
912        }
913
914        # Remove a potential $ENV{'HOME'} as tdir should be relative to pb's home
915        $tdir =~ s|\$ENV.+\}/||;
916
917        my $tm = $vtmout->{$ENV{'PBPROJ'}};
918
919        # ssh communication if not VE
920        # should use a hash instead...
921        my ($shcmd,$cpcmd,$cptarget,$cp2target);
922        if ($cmt ne "ve") {
923                my $keyfile = pb_ssh_get(0);
924                $shcmd = "ssh -i $keyfile -q -p $nport $mac";
925                $cpcmd = "scp -i $keyfile -p -P $nport";
926                $cptarget = "$mac:$tdir";
927                if ($cmt eq "vm") {
928                        $cp2target = "$mac:$bdir";
929                }
930        } else {
931                my $tp = $vepath->{$ENV{'PBPROJ'}};
932                $shcmd = "sudo chroot $tp/$v /bin/su - $sshlogin->{$ENV{'PBPROJ'}} -c ";
933                $cpcmd = "cp -a ";
934                $cptarget = "$tp/$tdir";
935                $cp2target = "$tp/$bdir";
936        }
937
938        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");
939        pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget");
940        # For VE we need to change the owner manually - To be tested if needed
941        #if ($cmt eq "ve") {
942        #pb_system("cd $cptarget ; sudo chown -R $sshlogin->{$ENV{'PBPROJ'}} .","$cmt chown in $cptarget to $sshlogin->{$ENV{'PBPROJ'}}");
943        #}
944        pb_system("$shcmd \"echo \'cd $tdir ; if [ -f pbscript ]; then ./pbscript; fi\' | bash\"","Executing pbscript on $cptarget if needed");
945        if (($cmt eq "vm") || ($cmt eq "ve")) {
946                # Get back info on pkg produced, compute their name and get them from the VM
947                pb_system("$cpcmd $cp2target/pbgen-$pbprojver-$pbprojtag $ENV{'PBBUILDDIR'} 2> /dev/null","Get package names in $cp2target");
948                open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
949                my $src = <KEEP>;
950                chomp($src);
951                close(KEEP);
952                $src =~ s/^ *//;
953                pb_mkdir_p("$ENV{'PBBUILDDIR'}/$odir/$over");
954                # Change pgben to make the next send2target happy
955                my $made = "";
956                open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to write $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
957                foreach my $p (split(/ +/,$src)) {
958                        my $j = basename($p);
959                        pb_system("$cpcmd $cp2target/\'$p\' $ENV{'PBBUILDDIR'}/$odir/$over 2> /dev/null","Package recovery of $j in $cp2target");
960                        $made="$made $odir/$over/$j" if (($dtype ne "rpm") || ($j !~ /.src.rpm$/));
961                }
962                print KEEP "$made\n";
963                close(KEEP);
964                pb_system("$shcmd \"rm -rf $tdir $bdir\"","$cmt cleanup");
965                pb_send2target("Packages","$odir"."_"."$over");
966                if ((! $vmexist) && ($cmt eq "vm")) {
967                        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)");
968                }
969                pb_rm_rf("$ENV{'PBBUILDDIR'}/$odir");
970        }
971}
972
973sub pb_script2v {
974        my $pbscript=shift;
975        my $vtype=shift;
976
977        # Prepare the script to be executed on the VM
978        # in $ENV{'PBDESTDIR'}/pbscript
979        if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript")) {
980                copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
981                chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
982        }
983
984        my ($vm,$all) = pb_get_v($vtype);
985        my ($vmexist,$vmpid) = (undef,undef);
986
987        foreach my $v (@$vm) {
988                # Launch the VM/VE
989                if ($vtype eq "vm") {
990                        ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
991
992                        # Skip that VM if something went wrong
993                        next if (($vmpid == 0) && ($vmexist ==0));
994                }
995
996                # Gather all required files to send them to the VM
997                # and launch the build through pbscript
998                pb_send2target("Script","$v",$vmexist,$vmpid);
999
1000        }
1001}
1002
1003sub pb_launchv {
1004        my $vtype = shift;
1005        my $v = shift;
1006        my $create = shift || 0;                # By default do not create a VM
1007
1008        die "No VM/VE defined, unable to launch" if (not defined $v);
1009        # Keep only the first VM in case many were given
1010        $v =~ s/,.*//;
1011
1012        # Which is our local arch ? (standardize on i386 for those platforms)
1013        my $arch = `uname -m`;
1014        chomp($arch);
1015        $arch =~ s/i.86/i386/;
1016
1017        # Launch the VMs/VEs
1018        if ($vtype eq "vm") {
1019                die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0));
1020
1021                my ($ptr,$vmopt,$vmport,$vmpath,$vmtmout,$vmsize) = pb_conf_get("vmtype","vmopt","vmport","vmpath","vmtmout","vmsize");
1022
1023                my $vmtype = $ptr->{$ENV{'PBPROJ'}};
1024                if (not defined $ENV{'PBVMOPT'}) {
1025                        $ENV{'PBVMOPT'} = "";
1026                }
1027                if (defined $vmopt->{$ENV{'PBPROJ'}}) {
1028                        $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/);
1029                }
1030                my $nport = $vmport->{$ENV{'PBPROJ'}};
1031                $nport = "$pbport" if (defined $pbport);
1032       
1033                my $cmd;
1034                my $vmcmd;              # has to be used for pb_check_ps
1035                my $vmm;                # has to be used for pb_check_ps
1036                if ($vmtype eq "qemu") {
1037                        my $qemucmd32;
1038                        my $qemucmd64;
1039                        if ($arch eq "x86_64") {
1040                                $qemucmd32 = "/usr/bin/qemu-system-i386";
1041                                $qemucmd64 = "/usr/bin/qemu";
1042                        } else {
1043                                $qemucmd32 = "/usr/bin/qemu";
1044                                $qemucmd64 = "/usr/bin/qemu-system-x86_64";
1045                        }
1046                if ($v =~ /x86_64/) {
1047                                $vmcmd = "$qemucmd64 -no-kqemu";
1048                        } else {
1049                                $vmcmd = "$qemucmd32";
1050                        }
1051                        $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu";
1052                        if ($create != 0) {
1053                                $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d";
1054                        }
1055                        $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm"
1056                } elsif ($vmtype eq "xen") {
1057                } elsif ($vmtype eq "vmware") {
1058                } else {
1059                        die "VM of type $vmtype not supported. Report to the dev team";
1060                }
1061                my ($tmpcmd,$void) = split(/ +/,$cmd);
1062                my $vmexist = pb_check_ps($tmpcmd,$vmm);
1063                my $vmpid = 0;
1064                if (! $vmexist) {
1065                        if ($create != 0) {
1066                                if (($vmtype eq "qemu") || ($vmtype eq "xen")) {
1067                                        pb_system("/usr/bin/qemu-img create -f qcow2 $vmm $vmsize->{$ENV{'PBPROJ'}}","Creating the QEMU VM");
1068                                } elsif ($vmtype eq "vmware") {
1069                                } else {
1070                                }
1071                        }
1072                        if (! -f "$vmm") {
1073                                pb_log(0,"Unable to find VM $vmm\n");
1074                        } else {
1075                                pb_system("$cmd &","Launching the VM $vmm");
1076                                pb_system("sleep $vmtmout->{$ENV{'PBPROJ'}}","Waiting for VM $v to come up");
1077                                $vmpid = pb_check_ps($tmpcmd,$vmm);
1078                        }
1079                } else {
1080                        pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n");
1081                }
1082                return($vmexist,$vmpid);
1083        # VE here
1084        } else {
1085                # Get VE context
1086                my ($ptr,$vepath,$vetmout,$verebuild,$veconf) = pb_conf_get("vetype","vepath","vetmout","verebuild","veconf");
1087                my $vetype = $ptr->{$ENV{'PBPROJ'}};
1088
1089                # Get distro context
1090                my ($name,$ver,$darch) = split(/-/,$v);
1091                chomp($darch);
1092                my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver);
1093
1094                if ($vetype eq "chroot") {
1095                        # Architecture consistency
1096                        if ($arch ne $darch) {
1097                                die "Unable to launch a VE of architecture $darch on a $arch platform" if (not (($darch eq "x86_64") && ($arch =~ /i?86/)));
1098                        }
1099
1100                        if (($create != 0) || ($verebuild->{$ENV{'PBPROJ'}} eq "true") || ($force == 1)) {
1101                                # We have to rebuild the chroot
1102                                if ($dtype eq "rpm") {
1103                                        pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1104                                        # Once setup we need to install some packages, the pb account, ...
1105                                        pb_system("sudo /usr/sbin/mock --install --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v su","Configuring the mock VE");
1106                                        #pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" --basedir=\"$vepath->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1107                                } elsif ($dtype eq "deb") {
1108                                        pb_system("","Creating the pbuilder VE");
1109                                } elsif ($dtype eq "ebuild") {
1110                                        die "Please teach the dev team how to build gentoo chroot";
1111                                } else {
1112                                        die "Unknown distribution type $dtype. Report to dev team";
1113                                }
1114                        }
1115                        # Nothing more to do for VE. No real launch
1116                } else {
1117                        die "VE of type $vetype not supported. Report to the dev team";
1118                }
1119        }
1120}
1121
1122sub pb_build2v {
1123
1124my $vtype = shift;
1125
1126# Prepare the script to be executed on the VM/VE
1127# in $ENV{'PBDESTDIR'}/pbscript
1128my ($ntp) = pb_conf_get($vtype."ntp");
1129my $vntp = $ntp->{$ENV{'PBPROJ'}};
1130
1131open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
1132print SCRIPT "#!/bin/bash\n";
1133print SCRIPT "echo ... Execution needed\n";
1134print SCRIPT "# This is in directory delivery\n";
1135print SCRIPT "# Setup the variables required for building\n";
1136print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n";
1137print SCRIPT "# Preparation for pb\n";
1138print SCRIPT "mv .pbrc \$HOME\n";
1139print SCRIPT "cd ..\n";
1140# Force new date to be in the future compared to the date of the tar file by adding 1 minute
1141my @date=pb_get_date();
1142$date[1]++;
1143my $upddate = strftime("%m%d%H%M%Y", @date);
1144print SCRIPT "echo Setting up date on $vntp...\n";
1145# Or use ntpdate if available TBC
1146print SCRIPT "sudo date $upddate\n";
1147# This exports avoids pb_env_init to deal with PBCONF stuff
1148print SCRIPT "export PBCONF=/tmp\n";
1149print SCRIPT "export PBVER=$ENV{'PBVER'}\n";
1150print SCRIPT "export PBTAG=$ENV{'PBTAG'}\n";
1151print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n";
1152print SCRIPT "# Build\n";
1153# Get list of packages to build
1154my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
1155@pkgs = @$ptr;
1156my $p = join(' ',@pkgs) if (@pkgs);
1157print SCRIPT "echo Building packages on $vtype...\n";
1158print SCRIPT "pb -p $ENV{'PBPROJ'} build2pkg $p\n";
1159close(SCRIPT);
1160chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
1161
1162my ($v,$all) = pb_get_v($vtype);
1163
1164# Send tar files when we do a global generation
1165pb_build2ssh() if ($all == 1);
1166
1167my ($vmexist,$vmpid) = (undef,undef);
1168
1169foreach my $v (@$v) {
1170        if ($vtype eq "vm") {
1171                # Launch the VM
1172                my ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
1173
1174                # Skip that VM if it something went wrong
1175                next if (($vmpid == 0) && ($vmexist == 0));
1176        }
1177        # Gather all required files to send them to the VM/VE
1178        # and launch the build through pbscript
1179        pb_send2target($vtype,"$v",$vmexist,$vmpid);
1180}
1181}
1182
1183
1184sub pb_newver {
1185
1186        die "-V Version parameter needed" if ((not defined $newver) || ($newver eq ""));
1187
1188        my ($scheme,$uri)=pb_cms_init($pbinit);
1189
1190        if ($scheme !~ /^svn/) {
1191                die "Only SVN is supported at the moment";
1192        }
1193        my $res = pb_cms_isdiff($scheme);
1194        die "You need to have no differences before creating a new version" if ($res != 0);
1195        my $cmsurl = pb_cms_getinfo($scheme,$ENV{'PBROOTDIR'},"URL:");
1196        my $newurl = dirname($cmsurl)."/$newver";
1197        pb_cms_copy($scheme,$cmsurl,$newurl);
1198        pb_cms_checkout($scheme,$newurl,"$ENV{'PBROOTDIR'}/../$newver");
1199        my $oldver=basename($cmsurl);
1200        open(FILE,"$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb";
1201        open(OUT,"> $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new";
1202        while(<FILE>) {
1203                s/projver\s+$ENV{'PBPROJ'}\s*=\s*$oldver/projver $ENV{'PBPROJ'} = $newver/;
1204                print OUT $_;
1205        }
1206        close(FILE);
1207        close(OUT);
1208        rename("$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new","$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb");
1209        pb_cms_checkin($scheme,"$ENV{'PBROOTDIR'}/../$newver");
1210}
1211
1212#
1213# Return the list of VMs/VEs we are working on
1214# $all is a flag to know if we return all of them
1215# or only some (if all we publish also tar files in addition to pkgs
1216#
1217sub pb_get_v {
1218
1219my $vtype = shift;
1220my @v;
1221my $all = 0;
1222my $vlist;
1223my $pbv = 'PBV';
1224
1225if ($vtype eq "vm") {
1226        $vlist = "vmlist";
1227} elsif ($vtype eq "ve") {
1228        $vlist = "velist";
1229}
1230# Get VM/VE list
1231if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) {
1232        my ($ptr) = pb_conf_get($vlist);
1233        $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}};
1234        $all = 1;
1235}
1236pb_log(2,"$vtype: $ENV{$pbv}\n");
1237@v = split(/,/,$ENV{$pbv});
1238return(\@v,$all);
1239}
1240
1241# Function to create a potentialy missing pb account on the VM/VE, and adds it to sudo
1242# Needs to use root account to connect to the VM/VE
1243# pb will take your local public SSH key to access
1244# the pb account in the VM later on if needed
1245sub pb_setup_v {
1246
1247my $vtype = shift;
1248
1249# Script generated
1250my $pbscript = "$ENV{'PBDESTDIR'}/setupv";
1251
1252# Name of the account to deal with for VM/VE
1253# Do not use the one passed potentially with -a
1254my ($pbaccount) = pb_conf_get($vtype."login");
1255
1256if ($vtype eq "vm") {
1257        # Prepare the key to be used and transfered remotely
1258        my $keyfile = pb_ssh_get(1);
1259       
1260        my ($vmhost,$vmport) = pb_conf_get("vmhost","vmport");
1261        my $nport = $vmport->{$ENV{'PBPROJ'}};
1262        $nport = "$pbport" if (defined $pbport);
1263
1264        pb_system("cat $keyfile.pub | ssh -q -p $nport -i $keyfile root\@$vmhost->{$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");
1265        # once this is done, we can do what we want on the VM remotely
1266}
1267
1268# Prepare the script to be executed on the VM/VE
1269# in $ENV{'PBDESTDIR'}/setupv
1270
1271open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
1272print SCRIPT << 'EOF';
1273#!/usr/bin/perl -w
1274
1275use strict;
1276use File::Copy;
1277
1278my $file="/etc/passwd";
1279open(PBFILE,$file) || die "Unable to open $file";
1280my $found = 0;
1281while (<PBFILE>) {
1282EOF
1283print SCRIPT << "EOF";
1284        \$found = 1 if (/^$pbaccount->{$ENV{'PBPROJ'}}:/);
1285EOF
1286print SCRIPT << 'EOF';
1287}
1288close(PBFILE);
1289
1290if ( $found == 0 ) {
1291        if ( ! -d "/home" ) {
1292                mkdir "/home";
1293        }
1294EOF
1295print SCRIPT << "EOF";
1296system "groupadd $pbaccount->{$ENV{'PBPROJ'}}";
1297system "useradd $pbaccount->{$ENV{'PBPROJ'}} -g $pbaccount->{$ENV{'PBPROJ'}} -m -d /home/$pbaccount->{$ENV{'PBPROJ'}}";
1298
1299# For pb
1300chdir "/home/$pbaccount->{$ENV{'PBPROJ'}}";
1301mkdir ".ssh",0700;
1302# Allow those accessing root to access the build account
1303copy("\$ENV{'HOME'}/.ssh/authorized_keys",".ssh/authorized_keys");
1304chmod 0600,".ssh/authorized_keys";
1305system 'chown -R $pbaccount->{$ENV{'PBPROJ'}}:$pbaccount->{$ENV{'PBPROJ'}} .ssh';
1306
1307EOF
1308print SCRIPT << 'EOF';
1309}
1310
1311# No passwd for build account only keys
1312$file="/etc/shadow";
1313open(PBFILE,$file) || die "Unable to open $file";
1314open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1315while (<PBFILE>) {
1316EOF
1317print SCRIPT << "EOF";
1318        s/^$pbaccount->{$ENV{'PBPROJ'}}:\!\!:/$pbaccount->{$ENV{'PBPROJ'}}:*:/;
1319        s/^$pbaccount->{$ENV{'PBPROJ'}}:\!:/$pbaccount->{$ENV{'PBPROJ'}}:*:/;   #SLES 9 e.g.
1320EOF
1321print SCRIPT << 'EOF';
1322        print PBOUT $_;
1323}
1324close(PBFILE);
1325close(PBOUT);
1326rename("$file.new",$file);
1327chmod 0640,$file;
1328
1329# pb has to be added to portage group on gentoo
1330
1331# Adapt sudoers
1332$file="/etc/sudoers";
1333open(PBFILE,$file) || die "Unable to open $file";
1334open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1335while (<PBFILE>) {
1336EOF
1337print SCRIPT << "EOF";
1338        next if (/^$pbaccount->{$ENV{'PBPROJ'}}   /);
1339EOF
1340print SCRIPT << 'EOF';
1341        s/Defaults[ \t]+requiretty//;
1342        print PBOUT $_;
1343}
1344close(PBFILE);
1345EOF
1346print SCRIPT << "EOF";
1347# This is needed in order to be able to halt the machine from the $pbaccount->{$ENV{'PBPROJ'}} account at least
1348print PBOUT "$pbaccount->{$ENV{'PBPROJ'}}   ALL=(ALL) NOPASSWD:ALL\n";
1349EOF
1350print SCRIPT << 'EOF';
1351close(PBOUT);
1352rename("$file.new",$file);
1353chmod 0440,$file;
1354
1355EOF
1356
1357my $SCRIPT = \*SCRIPT;
1358
1359pb_install_deps($SCRIPT);
1360
1361print SCRIPT << 'EOF';
1362# Suse wants sudoers as 640
1363if (($ddir eq "sles") || (($ddir eq "suse")) && ($dver ne "10.3")) {
1364        chmod 0640,$file;
1365}
1366
1367# Sync date
1368system "/usr/sbin/ntpdate ntp.pool.org";
1369
1370system "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 ..";
1371EOF
1372
1373# Adds pb_distro_init from ProjectBuilder::Distribution
1374foreach my $d (@INC) {
1375        my $f = "$d/ProjectBuilder/Distribution.pm";
1376        if (-f "$f") {
1377                open(PBD,"$f") || die "Unable to open $f";
1378                while (<PBD>) {
1379                        next if (/^package/);
1380                        next if (/^use Exporter/);
1381                        next if (/^\@our /);
1382                        print SCRIPT $_;
1383                }
1384                close(PBD);
1385                last;
1386        }
1387}
1388close(SCRIPT);
1389chmod 0755,"$pbscript";
1390return($pbscript);
1391}
1392
1393sub pb_install_deps {
1394
1395my $SCRIPT = shift;
1396
1397print {$SCRIPT} << 'EOF';
1398# We need to have that pb_distro_init function
1399# Get it from Project-Builder::Distribution
1400my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init(); 
1401print "distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n";
1402
1403# Get and install pb
1404if ( $ddir eq "fedora" ) {
1405        system "yum clean all";
1406        #system "yum update -y";
1407        my $arch=`uname -m`;
1408        my $opt = "";
1409        chomp($arch);
1410        if ($arch eq "x86_64") {
1411                $opt="--exclude=*.i?86";
1412        }
1413
1414        system "yum -y $opt install rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker";
1415} 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")) || ($ddir eq "slackware")) {
1416        # Suppose pkg are installed already
1417        system "rpm -e lsb 2>&1 > /dev/null";
1418        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 .. ";
1419} elsif ($ddir eq "suse") { 
1420        # New OpenSuSE
1421        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";
1422} elsif ( $dfam eq "md" ) {
1423                system "urpmi.update -a ; urpmi --auto rpm-build wget sudo patch ntp-client perl-DateManip";
1424} elsif ( $dfam eq "du" ) {
1425        if (( $dver eq "3.1" ) && ($ddir eq "debian")) {
1426                #system "apt-get update";
1427                system "apt-get -y install wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libdate-manip-perl";
1428        } else  {
1429                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";
1430        }
1431} elsif ( $dfam eq "gen" ) {
1432                system "emerge -u system ; emerge wget sudo ntp DateManip";
1433} else {
1434        print "No pkg to install\n";
1435}
1436EOF
1437}
1438
1439# Return the SSH key file to use
1440# Potentially create it if needed
1441
1442sub pb_ssh_get {
1443
1444my $create = shift || 0;        # Do not create keys by default
1445
1446# Check the SSH environment
1447my $keyfile = undef;
1448
1449# We have specific keys by default
1450$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa";
1451if (!(-e $keyfile) && ($create eq 1)) {
1452        pb_system("ssh-keygen -q -b 1024 -N '' -f $keyfile -t dsa","Generating SSH keys for pb");
1453}
1454
1455$keyfile = "$ENV{'HOME'}/.ssh/id_rsa" if (-s "$ENV{'HOME'}/.ssh/id_rsa");
1456$keyfile = "$ENV{'HOME'}/.ssh/id_dsa" if (-s "$ENV{'HOME'}/.ssh/id_dsa");
1457$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa" if (-s "$ENV{'HOME'}/.ssh/pb_dsa");
1458die "Unable to find your public ssh key under $keyfile" if (not defined $keyfile);
1459return($keyfile);
1460}
1461
1462
1463# Returns the pid of a running VM command using a specific VM file
1464sub pb_check_ps {
1465        my $vmcmd = shift;
1466        my $vmm = shift;
1467        my $vmexist = 0;                # FALSE by default
1468
1469        open(PS, "ps auxhww|") || die "Unable to call ps";
1470        while (<PS>) {
1471                next if (! /$vmcmd/);
1472                next if (! /$vmm/);
1473                my ($void1, $void2);
1474                ($void1, $vmexist, $void2) = split(/ +/);
1475                last;
1476        }
1477        return($vmexist);
1478}
1479
1480
1481sub pb_extract_build_files {
1482
1483my $src=shift;
1484my $dir=shift;
1485my $ddir=shift;
1486my @files;
1487
1488if ($src =~ /tar\.gz$/) {
1489        pb_system("tar xfpz $src $dir","Extracting build files");
1490} elsif ($src =~ /tar\.bz2$/) {
1491        pb_system("tar xfpj $src $dir","Extracting build files");
1492} else {
1493        die "Unknown compression algorithm for $src";
1494}
1495opendir(DIR,"$dir") || die "Unable to open directory $dir";
1496foreach my $f (readdir(DIR)) {
1497        next if ($f =~ /^\./);
1498        move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
1499        pb_log(2,"mv $dir/$f $ddir\n");
1500        push @files,"$ddir/$f";
1501}
1502closedir(DIR);
1503# Not enough but still a first cleanup
1504pb_rm_rf("$dir");
1505return(@files);
1506}
1507
1508sub pb_list_bfiles {
1509
1510my $dir = shift;
1511my $pbpkg = shift;
1512my $bfiles = shift;
1513my $pkgfiles = shift;
1514my $supfiles = shift;
1515
1516opendir(BDIR,"$dir") || die "Unable to open dir $dir: $!";
1517foreach my $f (readdir(BDIR)) {
1518        next if ($f =~ /^\./);
1519        $bfiles->{$f} = "$dir/$f";
1520        $bfiles->{$f} =~ s~$ENV{'PBROOTDIR'}~~;
1521        if (defined $supfiles->{$pbpkg}) {
1522                $pkgfiles->{$f} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/);
1523        }
1524}
1525closedir(BDIR);
1526}
1527
1528sub pb_syntax {
1529
1530my $exit_status = shift || -1;
1531my $verbose_level = shift || 0;
1532
1533my $filehandle = \*STDERR;
1534
1535$filehandle = \*STDOUT if ($exit_status == 0);
1536
1537pod2usage( { -message => "pb (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n",
1538             -exitval => $exit_status  ,
1539             -verbose => $verbose_level,
1540             -output  => $filehandle } );
1541}
Note: See TracBrowser for help on using the repository browser.