source: devel/pb/bin/pb @ 355

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

Fix a problem in build2vm where the new name of the distro wasn't correctly handled when trying to get packages pushed to the ftp server.

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