source: devel/pb/bin/pb @ 350

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

setupvm does 90% of the job now

  • 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                $cp2target = "$mac:$bdir";
928        } else {
929                my $tp = $vepath->{$ENV{'PBPROJ'}};
930                $shcmd = "sudo chroot $tp/$v /bin/su - $sshlogin->{$ENV{'PBPROJ'}} -c ";
931                $cpcmd = "cp -a ";
932                $cptarget = "$tp/$tdir";
933                $cp2target = "$tp/$bdir";
934        }
935
936        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");
937        pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget");
938        # For VE we need to change the owner manually - To be tested if needed
939        #if ($cmt eq "ve") {
940        #pb_system("cd $cptarget ; sudo chown -R $sshlogin->{$ENV{'PBPROJ'}} .","$cmt chown in $cptarget to $sshlogin->{$ENV{'PBPROJ'}}");
941        #}
942        pb_system("$shcmd \"echo \'cd $tdir ; if [ -f pbscript ]; then ./pbscript; fi\' | bash\"","Executing pbscript on $cptarget if needed");
943        if (($cmt eq "vm") || ($cmt eq "ve")) {
944                # Get back info on pkg produced, compute their name and get them from the VM
945                pb_system("$cpcmd $cp2target/pbgen-$pbprojver-$pbprojtag $ENV{'PBBUILDDIR'} 2> /dev/null","Get package names in $cp2target");
946                open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
947                my $src = <KEEP>;
948                chomp($src);
949                close(KEEP);
950                $src =~ s/^ *//;
951                pb_mkdir_p("$ENV{'PBBUILDDIR'}/$odir/$over");
952                # Change pgben to make the next send2target happy
953                my $made = "";
954                open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag") || die "Unable to write $ENV{'PBBUILDDIR'}/pbgen-$pbprojver-$pbprojtag";
955                foreach my $p (split(/ +/,$src)) {
956                        my $j = basename($p);
957                        pb_system("$cpcmd $cp2target/\'$p\' $ENV{'PBBUILDDIR'}/$odir/$over 2> /dev/null","Package recovery of $j in $cp2target");
958                        $made="$made $odir/$over/$j" if (($dtype ne "rpm") || ($j !~ /.src.rpm$/));
959                }
960                print KEEP "$made\n";
961                close(KEEP);
962                pb_system("$shcmd \"rm -rf $tdir $bdir\"","$cmt cleanup");
963                pb_send2target("Packages","$odir"."_"."$over");
964                if ((! $vmexist) && ($cmt eq "vm")) {
965                        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)");
966                }
967                pb_rm_rf("$ENV{'PBBUILDDIR'}/$odir");
968        }
969}
970
971sub pb_script2v {
972        my $pbscript=shift;
973        my $vtype=shift;
974
975        # Prepare the script to be executed on the VM
976        # in $ENV{'PBDESTDIR'}/pbscript
977        if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript")) {
978                copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
979                chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
980        }
981
982        my ($vm,$all) = pb_get_v($vtype);
983        my ($vmexist,$vmpid) = (undef,undef);
984
985        foreach my $v (@$vm) {
986                # Launch the VM/VE
987                if ($vtype eq "vm") {
988                        ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
989
990                        # Skip that VM if something went wrong
991                        next if (($vmpid == 0) && ($vmexist ==0));
992                }
993
994                # Gather all required files to send them to the VM
995                # and launch the build through pbscript
996                pb_send2target("Script","$v",$vmexist,$vmpid);
997
998        }
999}
1000
1001sub pb_launchv {
1002        my $vtype = shift;
1003        my $v = shift;
1004        my $create = shift || 0;                # By default do not create a VM
1005
1006        die "No VM/VE defined, unable to launch" if (not defined $v);
1007        # Keep only the first VM in case many were given
1008        $v =~ s/,.*//;
1009
1010        # Which is our local arch ? (standardize on i386 for those platforms)
1011        my $arch = `uname -m`;
1012        chomp($arch);
1013        $arch =~ s/i.86/i386/;
1014
1015        # Launch the VMs/VEs
1016        if ($vtype eq "vm") {
1017                die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0));
1018
1019                my ($ptr,$vmopt,$vmport,$vmpath,$vmtmout,$vmsize) = pb_conf_get("vmtype","vmopt","vmport","vmpath","vmtmout","vmsize");
1020
1021                my $vmtype = $ptr->{$ENV{'PBPROJ'}};
1022                if (not defined $ENV{'PBVMOPT'}) {
1023                        $ENV{'PBVMOPT'} = "";
1024                }
1025                if (defined $vmopt->{$ENV{'PBPROJ'}}) {
1026                        $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/);
1027                }
1028                my $nport = $vmport->{$ENV{'PBPROJ'}};
1029                $nport = "$pbport" if (defined $pbport);
1030       
1031                my $cmd;
1032                my $vmcmd;              # has to be used for pb_check_ps
1033                my $vmm;                # has to be used for pb_check_ps
1034                if ($vmtype eq "qemu") {
1035                        my $qemucmd32;
1036                        my $qemucmd64;
1037                        if ($arch eq "x86_64") {
1038                                $qemucmd32 = "/usr/bin/qemu-system-i386";
1039                                $qemucmd64 = "/usr/bin/qemu";
1040                        } else {
1041                                $qemucmd32 = "/usr/bin/qemu";
1042                                $qemucmd64 = "/usr/bin/qemu-system-x86_64";
1043                        }
1044                if ($v =~ /x86_64/) {
1045                                $vmcmd = "$qemucmd64 -no-kqemu";
1046                        } else {
1047                                $vmcmd = "$qemucmd32";
1048                        }
1049                        $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu";
1050                        if ($create != 0) {
1051                                $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d";
1052                        }
1053                        $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm"
1054                } elsif ($vmtype eq "xen") {
1055                } elsif ($vmtype eq "vmware") {
1056                } else {
1057                        die "VM of type $vmtype not supported. Report to the dev team";
1058                }
1059                my ($tmpcmd,$void) = split(/ +/,$cmd);
1060                my $vmexist = pb_check_ps($tmpcmd,$vmm);
1061                my $vmpid = 0;
1062                if (! $vmexist) {
1063                        if ($create != 0) {
1064                                if (($vmtype eq "qemu") || ($vmtype eq "xen")) {
1065                                        pb_system("/usr/bin/qemu-img create -f qcow2 $vmm $vmsize->{$ENV{'PBPROJ'}}","Creating the QEMU VM");
1066                                } elsif ($vmtype eq "vmware") {
1067                                } else {
1068                                }
1069                        }
1070                        if (! -f "$vmm") {
1071                                pb_log(0,"Unable to find VM $vmm\n");
1072                        } else {
1073                                pb_system("$cmd &","Launching the VM $vmm");
1074                                pb_system("sleep $vmtmout->{$ENV{'PBPROJ'}}","Waiting for VM $v to come up");
1075                                $vmpid = pb_check_ps($tmpcmd,$vmm);
1076                        }
1077                } else {
1078                        pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n");
1079                }
1080                return($vmexist,$vmpid);
1081        # VE here
1082        } else {
1083                # Get VE context
1084                my ($ptr,$vepath,$vetmout,$verebuild,$veconf) = pb_conf_get("vetype","vepath","vetmout","verebuild","veconf");
1085                my $vetype = $ptr->{$ENV{'PBPROJ'}};
1086
1087                # Get distro context
1088                my ($name,$ver,$darch) = split(/-/,$v);
1089                chomp($darch);
1090                my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver);
1091
1092                if ($vetype eq "chroot") {
1093                        # Architecture consistency
1094                        if ($arch ne $darch) {
1095                                die "Unable to launch a VE of architecture $darch on a $arch platform" if (not (($darch eq "x86_64") && ($arch =~ /i?86/)));
1096                        }
1097
1098                        if (($create != 0) || ($verebuild->{$ENV{'PBPROJ'}} eq "true") || ($force == 1)) {
1099                                # We have to rebuild the chroot
1100                                if ($dtype eq "rpm") {
1101                                        pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1102                                        # Once setup we need to install some packages, the pb account, ...
1103                                        pb_system("sudo /usr/sbin/mock --install --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v su","Configuring the mock VE");
1104                                        #pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" --basedir=\"$vepath->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE");
1105                                } elsif ($dtype eq "deb") {
1106                                        pb_system("","Creating the pbuilder VE");
1107                                } elsif ($dtype eq "ebuild") {
1108                                        die "Please teach the dev team how to build gentoo chroot";
1109                                } else {
1110                                        die "Unknown distribution type $dtype. Report to dev team";
1111                                }
1112                        }
1113                        # Nothing more to do for VE. No real launch
1114                } else {
1115                        die "VE of type $vetype not supported. Report to the dev team";
1116                }
1117        }
1118}
1119
1120sub pb_build2v {
1121
1122my $vtype = shift;
1123
1124# Prepare the script to be executed on the VM/VE
1125# in $ENV{'PBDESTDIR'}/pbscript
1126my ($ntp) = pb_conf_get($vtype."ntp");
1127my $vntp = $ntp->{$ENV{'PBPROJ'}};
1128
1129open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript";
1130print SCRIPT "#!/bin/bash\n";
1131print SCRIPT "echo ... Execution needed\n";
1132print SCRIPT "# This is in directory delivery\n";
1133print SCRIPT "# Setup the variables required for building\n";
1134print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n";
1135print SCRIPT "# Preparation for pb\n";
1136print SCRIPT "mv .pbrc \$HOME\n";
1137print SCRIPT "cd ..\n";
1138# Force new date to be in the future compared to the date of the tar file by adding 1 minute
1139my @date=pb_get_date();
1140$date[1]++;
1141my $upddate = strftime("%m%d%H%M%Y", @date);
1142print SCRIPT "echo Setting up date on $vntp...\n";
1143# Or use ntpdate if available TBC
1144print SCRIPT "sudo date $upddate\n";
1145# This exports avoids pb_env_init to deal with PBCONF stuff
1146print SCRIPT "export PBCONF=/tmp\n";
1147print SCRIPT "export PBVER=$ENV{'PBVER'}\n";
1148print SCRIPT "export PBTAG=$ENV{'PBTAG'}\n";
1149print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n";
1150print SCRIPT "# Build\n";
1151# Get list of packages to build
1152my $ptr = pb_get_pkg($defpkgdir,$extpkgdir);
1153@pkgs = @$ptr;
1154my $p = join(' ',@pkgs) if (@pkgs);
1155print SCRIPT "echo Building packages on $vtype...\n";
1156print SCRIPT "pb -p $ENV{'PBPROJ'} build2pkg $p\n";
1157close(SCRIPT);
1158chmod 0755,"$ENV{'PBDESTDIR'}/pbscript";
1159
1160my ($v,$all) = pb_get_v($vtype);
1161
1162# Send tar files when we do a global generation
1163pb_build2ssh() if ($all == 1);
1164
1165my ($vmexist,$vmpid) = (undef,undef);
1166
1167foreach my $v (@$v) {
1168        if ($vtype eq "vm") {
1169                # Launch the VM
1170                my ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
1171
1172                # Skip that VM if it something went wrong
1173                next if (($vmpid == 0) && ($vmexist == 0));
1174        }
1175        # Gather all required files to send them to the VM/VE
1176        # and launch the build through pbscript
1177        pb_send2target($vtype,"$v",$vmexist,$vmpid);
1178}
1179}
1180
1181
1182sub pb_newver {
1183
1184        die "-V Version parameter needed" if ((not defined $newver) || ($newver eq ""));
1185
1186        my ($scheme,$uri)=pb_cms_init($pbinit);
1187
1188        if ($scheme !~ /^svn/) {
1189                die "Only SVN is supported at the moment";
1190        }
1191        my $res = pb_cms_isdiff($scheme);
1192        die "You need to have no differences before creating a new version" if ($res != 0);
1193        my $cmsurl = pb_cms_getinfo($scheme,$ENV{'PBROOTDIR'},"URL:");
1194        my $newurl = dirname($cmsurl)."/$newver";
1195        pb_cms_copy($scheme,$cmsurl,$newurl);
1196        pb_cms_checkout($scheme,$newurl,"$ENV{'PBROOTDIR'}/../$newver");
1197        my $oldver=basename($cmsurl);
1198        open(FILE,"$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb";
1199        open(OUT,"> $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new";
1200        while(<FILE>) {
1201                s/projver\s+$ENV{'PBPROJ'}\s*=\s*$oldver/projver $ENV{'PBPROJ'} = $newver/;
1202                print OUT $_;
1203        }
1204        close(FILE);
1205        close(OUT);
1206        rename("$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb.new","$ENV{'PBROOTDIR'}/../$newver/pbconf/$ENV{'PBPROJ'}.pb");
1207        pb_cms_checkin($scheme,"$ENV{'PBROOTDIR'}/../$newver");
1208}
1209
1210#
1211# Return the list of VMs/VEs we are working on
1212# $all is a flag to know if we return all of them
1213# or only some (if all we publish also tar files in addition to pkgs
1214#
1215sub pb_get_v {
1216
1217my $vtype = shift;
1218my @v;
1219my $all = 0;
1220my $vlist;
1221my $pbv = 'PBV';
1222
1223if ($vtype eq "vm") {
1224        $vlist = "vmlist";
1225} elsif ($vtype eq "ve") {
1226        $vlist = "velist";
1227}
1228# Get VM/VE list
1229if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) {
1230        my ($ptr) = pb_conf_get($vlist);
1231        $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}};
1232        $all = 1;
1233}
1234pb_log(2,"$vtype: $ENV{$pbv}\n");
1235@v = split(/,/,$ENV{$pbv});
1236return(\@v,$all);
1237}
1238
1239# Function to create a potentialy missing pb account on the VM/VE, and adds it to sudo
1240# Needs to use root account to connect to the VM/VE
1241# pb will take your local public SSH key to access
1242# the pb account in the VM later on if needed
1243sub pb_setup_v {
1244
1245my $vtype = shift;
1246
1247# Script generated
1248my $pbscript = "$ENV{'PBDESTDIR'}/setupv";
1249
1250# Name of the account to deal with for VM/VE
1251# Do not use the one passed potentially with -a
1252my ($pbaccount) = pb_conf_get($vtype."login");
1253
1254if ($vtype eq "vm") {
1255        # Prepare the key to be used and transfered remotely
1256        my $keyfile = pb_ssh_get(1);
1257       
1258        my ($vmhost,$vmport) = pb_conf_get("vmhost","vmport");
1259        my $nport = $vmport->{$ENV{'PBPROJ'}};
1260        $nport = "$pbport" if (defined $pbport);
1261
1262        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");
1263        # once this is done, we can do what we want on the VM remotely
1264}
1265
1266# Prepare the script to be executed on the VM/VE
1267# in $ENV{'PBDESTDIR'}/setupv
1268
1269open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
1270print SCRIPT << 'EOF';
1271#!/usr/bin/perl -w
1272
1273use strict;
1274use File::Copy;
1275
1276my $file="/etc/passwd";
1277open(PBFILE,$file) || die "Unable to open $file";
1278my $found = 0;
1279while (<PBFILE>) {
1280EOF
1281print SCRIPT << "EOF";
1282        \$found = 1 if (/^$pbaccount->{$ENV{'PBPROJ'}}:/);
1283EOF
1284print SCRIPT << 'EOF';
1285}
1286close(PBFILE);
1287
1288if ( $found == 0 ) {
1289        if ( ! -d "/home" ) {
1290                mkdir "/home";
1291        }
1292EOF
1293print SCRIPT << "EOF";
1294system "groupadd $pbaccount->{$ENV{'PBPROJ'}}";
1295system "useradd $pbaccount->{$ENV{'PBPROJ'}} -g $pbaccount->{$ENV{'PBPROJ'}} -m -d /home/$pbaccount->{$ENV{'PBPROJ'}}";
1296
1297# For pb
1298chdir "/home/$pbaccount->{$ENV{'PBPROJ'}}";
1299mkdir ".ssh",0700;
1300# Allow those accessing root to access the build account
1301copy("\$ENV{'HOME'}/.ssh/authorized_keys",".ssh/authorized_keys");
1302chmod 0600,".ssh/authorized_keys";
1303system 'chown -R $pbaccount->{$ENV{'PBPROJ'}}:$pbaccount->{$ENV{'PBPROJ'}} .ssh';
1304
1305EOF
1306print SCRIPT << 'EOF';
1307}
1308
1309# No passwd for build account only keys
1310$file="/etc/shadow";
1311open(PBFILE,$file) || die "Unable to open $file";
1312open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1313while (<PBFILE>) {
1314EOF
1315print SCRIPT << "EOF";
1316        s/^$pbaccount->{$ENV{'PBPROJ'}}:\!\!:/$pbaccount->{$ENV{'PBPROJ'}}:*:/;
1317        s/^$pbaccount->{$ENV{'PBPROJ'}}:\!:/$pbaccount->{$ENV{'PBPROJ'}}:*:/;   #SLES 9 e.g.
1318EOF
1319print SCRIPT << 'EOF';
1320        print PBOUT $_;
1321}
1322close(PBFILE);
1323close(PBOUT);
1324rename("$file.new",$file);
1325chmod 0640,$file;
1326
1327# pb has to be added to portage group on gentoo
1328
1329# Adapt sudoers
1330$file="/etc/sudoers";
1331open(PBFILE,$file) || die "Unable to open $file";
1332open(PBOUT,"> $file.new") || die "Unable to open $file.new";
1333while (<PBFILE>) {
1334EOF
1335print SCRIPT << "EOF";
1336        next if (/^$pbaccount->{$ENV{'PBPROJ'}}   /);
1337EOF
1338print SCRIPT << 'EOF';
1339        s/Defaults[ \t]+requiretty//;
1340        print PBOUT $_;
1341}
1342close(PBFILE);
1343EOF
1344print SCRIPT << "EOF";
1345# This is needed in order to be able to halt the machine from the $pbaccount->{$ENV{'PBPROJ'}} account at least
1346print PBOUT "$pbaccount->{$ENV{'PBPROJ'}}   ALL=(ALL) NOPASSWD:ALL\n";
1347EOF
1348print SCRIPT << 'EOF';
1349close(PBOUT);
1350rename("$file.new",$file);
1351chmod 0440,$file;
1352
1353EOF
1354
1355my $SCRIPT = \*SCRIPT;
1356
1357pb_install_deps($SCRIPT);
1358
1359print SCRIPT << 'EOF';
1360# Suse wants sudoers as 640
1361if (($ddir eq "sles") || (($ddir eq "suse")) && ($dver ne "10.3")) {
1362        chmod 0640,$file;
1363}
1364
1365# Sync date
1366system "/usr/sbin/ntpdate ntp.pool.org";
1367
1368system "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 ..";
1369EOF
1370
1371# Adds pb_distro_init from ProjectBuilder::Distribution
1372foreach my $d (@INC) {
1373        my $f = "$d/ProjectBuilder/Distribution.pm";
1374        if (-f "$f") {
1375                open(PBD,"$f") || die "Unable to open $f";
1376                while (<PBD>) {
1377                        next if (/^package/);
1378                        next if (/^use Exporter/);
1379                        next if (/^\@our /);
1380                        print SCRIPT $_;
1381                }
1382                close(PBD);
1383                last;
1384        }
1385}
1386close(SCRIPT);
1387chmod 0755,"$pbscript";
1388return($pbscript);
1389}
1390
1391sub pb_install_deps {
1392
1393my $SCRIPT = shift;
1394
1395print {$SCRIPT} << 'EOF';
1396# We need to have that pb_distro_init function
1397# Get it from Project-Builder::Distribution
1398my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init(); 
1399print "distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n";
1400
1401# Get and install pb
1402if ( $ddir eq "fedora" ) {
1403        system "yum clean all";
1404        #system "yum update -y";
1405        my $arch=`uname -m`;
1406        my $opt = "";
1407        chomp($arch);
1408        if ($arch eq "x86_64") {
1409                $opt="--exclude=*.i?86";
1410        }
1411
1412        system "yum -y $opt install rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker";
1413} 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"))) {
1414        # Suppose pkg are installed already
1415        system "rpm -e lsb 2>&1 > /dev/null";
1416        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 .. ";
1417} elsif ($ddir eq "suse") { 
1418        # New OpenSuSE
1419        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";
1420} elsif ( $dfam eq "md" ) {
1421                system "urpmi.update -a ; urpmi --auto rpm-build wget sudo patch ntp-client perl-DateManip";
1422} elsif ( $dfam eq "du" ) {
1423        if (( $dver eq "3.1" ) && ($ddir eq "debian")) {
1424                #system "apt-get update";
1425                system "apt-get -y install wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libdate-manip-perl";
1426        } else  {
1427                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";
1428        }
1429} elsif ( $dfam eq "gen" ) {
1430                system "emerge -u system ; emerge wget sudo ntp DateManip";
1431} else {
1432        print "No pkg to install\n";
1433}
1434EOF
1435}
1436
1437# Return the SSH key file to use
1438# Potentially create it if needed
1439
1440sub pb_ssh_get {
1441
1442my $create = shift || 0;        # Do not create keys by default
1443
1444# Check the SSH environment
1445my $keyfile = undef;
1446
1447# We have specific keys by default
1448$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa";
1449if (!(-e $keyfile) && ($create eq 1)) {
1450        pb_system("ssh-keygen -q -b 1024 -N '' -f $keyfile -t dsa","Generating SSH keys for pb");
1451}
1452
1453$keyfile = "$ENV{'HOME'}/.ssh/id_rsa" if (-s "$ENV{'HOME'}/.ssh/id_rsa");
1454$keyfile = "$ENV{'HOME'}/.ssh/id_dsa" if (-s "$ENV{'HOME'}/.ssh/id_dsa");
1455$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa" if (-s "$ENV{'HOME'}/.ssh/pb_dsa");
1456die "Unable to find your public ssh key under $keyfile" if (not defined $keyfile);
1457return($keyfile);
1458}
1459
1460
1461# Returns the pid of a running VM command using a specific VM file
1462sub pb_check_ps {
1463        my $vmcmd = shift;
1464        my $vmm = shift;
1465        my $vmexist = 0;                # FALSE by default
1466
1467        open(PS, "ps auxhww|") || die "Unable to call ps";
1468        while (<PS>) {
1469                next if (! /$vmcmd/);
1470                next if (! /$vmm/);
1471                my ($void1, $void2);
1472                ($void1, $vmexist, $void2) = split(/ +/);
1473                last;
1474        }
1475        return($vmexist);
1476}
1477
1478
1479sub pb_extract_build_files {
1480
1481my $src=shift;
1482my $dir=shift;
1483my $ddir=shift;
1484my @files;
1485
1486if ($src =~ /tar\.gz$/) {
1487        pb_system("tar xfpz $src $dir","Extracting build files");
1488} elsif ($src =~ /tar\.bz2$/) {
1489        pb_system("tar xfpj $src $dir","Extracting build files");
1490} else {
1491        die "Unknown compression algorithm for $src";
1492}
1493opendir(DIR,"$dir") || die "Unable to open directory $dir";
1494foreach my $f (readdir(DIR)) {
1495        next if ($f =~ /^\./);
1496        move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
1497        pb_log(2,"mv $dir/$f $ddir\n");
1498        push @files,"$ddir/$f";
1499}
1500closedir(DIR);
1501# Not enough but still a first cleanup
1502pb_rm_rf("$dir");
1503return(@files);
1504}
1505
1506sub pb_list_bfiles {
1507
1508my $dir = shift;
1509my $pbpkg = shift;
1510my $bfiles = shift;
1511my $pkgfiles = shift;
1512my $supfiles = shift;
1513
1514opendir(BDIR,"$dir") || die "Unable to open dir $dir: $!";
1515foreach my $f (readdir(BDIR)) {
1516        next if ($f =~ /^\./);
1517        $bfiles->{$f} = "$dir/$f";
1518        $bfiles->{$f} =~ s~$ENV{'PBROOTDIR'}~~;
1519        if (defined $supfiles->{$pbpkg}) {
1520                $pkgfiles->{$f} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/);
1521        }
1522}
1523closedir(BDIR);
1524}
1525
1526sub pb_syntax {
1527
1528my $exit_status = shift || -1;
1529my $verbose_level = shift || 0;
1530
1531my $filehandle = \*STDERR;
1532
1533$filehandle = \*STDOUT if ($exit_status == 0);
1534
1535pod2usage( { -message => "pb (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n",
1536             -exitval => $exit_status  ,
1537             -verbose => $verbose_level,
1538             -output  => $filehandle } );
1539}
Note: See TracBrowser for help on using the repository browser.