source: ProjectBuilder/devel/pb/bin/pb@ 349

Last change on this file since 349 was 349, checked in by Bruno Cornec, 16 years ago

First working steps for setupvm

  • Property svn:executable set to *
File size: 47.0 KB
Line 
1#!/usr/bin/perl -w
2
3eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
4 if 0; # not running under some shell
5#
6# Project Builder main application
7#
8# $Id$
9#
10# Copyright B. Cornec 2007
11# Provided under the GPL v2
12
13# Syntax: see at end
14
15use strict 'vars';
16use Getopt::Long qw(:config auto_abbrev no_ignore_case);
17use Pod::Usage;
18use Data::Dumper;
19use English;
20use File::Basename;
21use File::Copy;
22use Time::localtime qw(localtime);
23use POSIX qw(strftime);
24
25# Global variables
26use lib qw (lib);
27use ProjectBuilder::Distribution;
28use ProjectBuilder::Version;
29use ProjectBuilder::Base;
30
31my %opts; # CLI Options
32my $action; # action to realize
33my $test = "FALSE"; # Not used
34my $force = 0; # Force VE/VM rebuild
35my $option = ""; # Not used
36my @pkgs; # list of packages
37my $pbtag; # Global Tag variable
38my $pbver; # Global Version variable
39my $pbscript; # Name of the script
40my %pbver; # per package
41my %pbtag; # per package
42my $pbrev; # Global REVISION variable
43my $pbaccount; # Login to use to connect to the VM
44my $pbport; # Port to use to connect to the VM
45my $newver; # New version to create
46my $iso; # ISO image for the VM to create
47
48my @date = pb_get_date();
49my $pbdate = strftime("%Y-%m-%d", @date);
50
51=pod
52
53=head1 NAME
54
55pb, aka project-builder.org - builds packages for your projects
56
57=head1 DESCRIPTION
58
59pb helps you build various packages directly from your project sources.
60Those sources could be handled by a CMS (Configuration Management System)
61such as Subversion, CVS, ... or being a simple reference to a compressed tar file.
62It's based on a set of configuration files, a set of provided macros to help
63you keeping build files as generic as possible. For example, a single .spec
64file should be required to generate for all rpm based distributions, even
65if you could also have multiple .spec files if required.
66
67=head1 SYNOPSIS
68
69pb [-vhq][-r pbroot][-p project][[-s script -a account -P port][-m mach-1[,...]]][-i iso] <action> [<pkg1> ...]
70
71pb [--verbose][--help][--man][--quiet][--revision pbroot][--project project][[--script script --account account --port port][--machine mach-1[,...]]][--iso iso] <action> [<pkg1> ...]
72
73=head1 OPTIONS
74
75=over 4
76
77=item B<-v|--verbose>
78
79Print a brief help message and exits.
80
81=item B<-q|--quiet>
82
83Do not print any output.
84
85=item B<-h|--help>
86
87Print a brief help message and exits.
88
89=item B<--man>
90
91Prints the manual page and exits.
92
93=item B<-m|--machine machine1[,machine2,...]>
94
95Name of the Virtual Machines (VM) or Virtual Environments (VE) you want to build on (coma separated).
96All if none precised (or use the env variable PBV).
97
98=item B<-s|--script script>
99
100Name of the script you want to execute on the related VMs or VEs.
101
102=item B<-i|--iso iso_image>
103
104Name of the ISO image of the distribution you want to install on the related VMs.
105
106=item B<-a|--account account>
107
108Name of the account to use to connect on the related VMs.
109
110=item B<-P|--port port_number>
111
112Port number to use to connect on the related VMs.\n";
113
114=item B<-p|--project project_name>
115
116Name of the project you're working on (or use the env variable PBPROJ)
117
118=item B<-r|--revision revision>
119
120Path Name of the project revision under the CMS (or use the env variable PBROOT)
121
122=item B<-V|--version new_version>
123
124New version of the project to create based on the current one.
125
126=back
127
128=head1 ARGUMENTS
129
130<action> can be:
131
132=over 4
133
134=item B<cms2build>
135
136Create tar files for the project under your CMS.
137CMS supported are SVN and CVS
138parameters are packages to build
139if not using default list
140
141=item B<build2pkg>
142
143Create packages for your running distribution
144
145=item B<cms2pkg>
146
147cms2build + build2pkg
148
149=item B<build2ssh>
150
151Send the tar files to a SSH host
152
153=item B<cms2ssh>
154
155cms2build + build2ssh
156
157=item B<pkg2ssh>
158
159Send the packages built to a SSH host
160
161=item B<build2vm>
162
163Create packages in VMs, launching them if needed
164and send those packages to a SSH host once built
165VM type supported are QEMU
166
167=item B<build2ve>
168
169Create packages in VEs, creating it if needed
170and send those packages to a SSH host once built
171
172=item B<cms2vm>
173
174cms2build + build2vm
175
176=item B<cms2ve>
177
178cms2build + build2ve
179
180=item B<launchvm>
181
182Launch one virtual machine
183
184=item B<launchve>
185
186Launch one virtual environment
187
188=item B<script2vm>
189
190Launch one virtual machine if needed
191and executes a script on it
192
193=item B<script2ve>
194
195Execute a script in a virtual environment
196
197=item B<newvm>
198
199Create a new virtual machine
200
201=item B<newve>
202
203Create a new virtual environment
204
205=item B<setupvm>
206
207Setup a virtual machine for pb usage
208
209=item B<setupve>
210
211Setup a virtual environment for pb usage
212
213=item B<newver>
214
215Create a new version of the project derived
216from the current one
217
218=item B<newproj>
219
220Create a new project and a template set of
221configuration files under pbconf
222
223=back
224
225<pkgs> can be a list of packages, the keyword 'all' or nothing, in which case the default list of packages is taken (corresponding to the defpkgdir list of arguments in the configuration file).
226
227=head1 WEB SITES
228
229The main Web site of the project is available at L<http://www.project-builder.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
230
231=head1 USER MAILING LIST
232
233None exists for the moment.
234
235=head1 CONFIGURATION FILES
236
237Each pb user may have a configuration in F<$HOME/.pbrc>. The values in this file may overwrite any other configuration file value.
238
239Here is an example of such a configuration file:
240
241 #
242 # Define for each project the URL of its pbconf repository
243 # No default option allowed here as they need to be all different
244 #
245 # URL of the pbconf content
246 # This is the format of a classical URL with the extension of additional schema such as
247 # svn+ssh, cvs+ssh, ...
248 #
249 pbconfurl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe/pbconf
250
251 # This is normaly defined in the project's configuration file
252 # Url of the project
253 #
254 pburl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe
255
256 # All these URLs needs to be defined here as the are the entry point
257 # for how to build packages for the project
258 #
259 pbconfurl pb = svn+ssh://svn.project-builder.org/mondo/svn/pb/pbconf
260 pbconfurl mondorescue = svn+ssh://svn.project-builder.org/mondo/svn/project-builder/mondorescue/pbconf
261 pbconfurl collectl = svn+ssh://bruno@svn.mondorescue.org/mondo/svn/project-builder/collectl/pbconf
262 pbconfurl netperf = svn+ssh://svn.mondorescue.org/mondo/svn/project-builder/netperf/pbconf
263
264 # Under that dir will take place everything related to pb
265 # If you want to use VMs/chroot/..., then use $ENV{'HOME'} to make it portable
266 # to your VMs/chroot/...
267 # if not defined then /var/cache
268 pbdefdir default = $ENV{'HOME'}/project-builder
269 pbdefdir pb = $ENV{'HOME'}
270 pbdefdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
271 pbdefdir mondorescue = $ENV{'HOME'}/mondo/svn
272
273 # pbconfdir points to the directory where the CMS content of the pbconfurl is checked out
274 # If not defined, pbconfdir is under pbdefdir/pbproj/pbconf
275 pbconfdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs/pbconf
276 pbconfdir mondorescue = $ENV{'HOME'}/mondo/svn/pbconf
277
278 # pbdir points to the directory where the CMS content of the pburl is checked out
279 # If not defined, pbdir is under pbdefdir/pbproj
280 # Only defined if we have access to the dev of the project
281 pbdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
282 pbdir mondorescue = $ENV{'HOME'}/mondo/svn
283
284 # -daemonize doesn't work with qemu 0.8.2
285 vmopt default = -m 384
286
287=head1 AUTHORS
288
289The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
290
291=head1 COPYRIGHT
292
293Project-Builder.org is distributed under the GPL v2.0 license
294described in the file C<COPYING> included with the distribution.
295
296=cut
297
298# ---------------------------------------------------------------------------
299
300# Old syntax
301#getopts('a:fhi:l:m:P:p:qr:s:vV:',\%opts);
302
303my ($projectbuilderver,$projectbuilderrev) = pb_version_init();
304
305GetOptions("help|?|h" => \$opts{'h'},
306 "man" => \$opts{'man'},
307 "verbose|v+" => \$opts{'v'},
308 "quiet|q" => \$opts{'q'},
309 "log-files|l=s" => \$opts{'l'},
310 "force|f" => \$opts{'f'},
311 "account|a=s" => \$opts{'a'},
312 "revision|r=s" => \$opts{'r'},
313 "script|s=s" => \$opts{'s'},
314 "machines|mock|m=s" => \$opts{'m'},
315 "port|P=i" => \$opts{'P'},
316 "project|p=s" => \$opts{'p'},
317 "iso|i=s" => \$opts{'i'},
318 "version|V=s" => \$opts{'V'},
319) || pb_syntax(-1,0);
320
321if (defined $opts{'h'}) {
322 pb_syntax(0,1);
323}
324if (defined $opts{'man'}) {
325 pb_syntax(0,2);
326}
327if (defined $opts{'v'}) {
328 $debug = $opts{'v'};
329 pb_log(0,"Debug value: $debug\n");
330}
331if (defined $opts{'f'}) {
332 $force=1;
333}
334if (defined $opts{'q'}) {
335 $debug=-1;
336}
337if (defined $opts{'l'}) {
338 open(LOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!";
339 $LOG = \*LOG;
340 $debug = 0 if ($debug == -1);
341 }
342pb_log_init($debug, $LOG);
343
344# Handle root of the project if defined
345if (defined $opts{'r'}) {
346 $ENV{'PBROOTDIR'} = $opts{'r'};
347}
348# Handle virtual machines if any
349if (defined $opts{'m'}) {
350 $ENV{'PBV'} = $opts{'m'};
351}
352if (defined $opts{'s'}) {
353 $pbscript = $opts{'s'};
354}
355if (defined $opts{'a'}) {
356 $pbaccount = $opts{'a'};
357 die "option -a requires a -s script option" if (not defined $pbscript);
358}
359if (defined $opts{'P'}) {
360 $pbport = $opts{'P'};
361}
362if (defined $opts{'V'}) {
363 $newver = $opts{'V'};
364}
365if (defined $opts{'i'}) {
366 $iso = $opts{'i'};
367}
368
369# Get Action
370$action = shift @ARGV;
371die pb_syntax(-1,1) if (not defined $action);
372
373my ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir);
374my $pbinit = undef;
375$pbinit = 1 if ($action =~ /^newproj$/);
376
377# Handles project name if any
378# And get global params
379if (defined $opts{'p'}) {
380 ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir)
381 = pb_env_init($opts{'p'},$pbinit);
382} else {
383 ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir)
384 = pb_env_init(undef,$pbinit);
385}
386
387pb_log(0,"Project: $ENV{'PBPROJ'}\n");
388pb_log(0,"Action: $action\n");
389
390# Keep those project values to store them at the end each time
391my $pbprojtag = $ENV{'PBTAG'};
392my $pbprojver = $ENV{'PBVER'};
393
394# Act depending on action
395if ($action =~ /^cms2build$/) {
396 pb_cms2build();
397} elsif ($action =~ /^build2pkg$/) {
398 pb_build2pkg();
399} elsif ($action =~ /^cms2pkg$/) {
400 pb_cms2build();
401 pb_build2pkg();
402} elsif ($action =~ /^build2ssh$/) {
403 pb_build2ssh();
404} elsif ($action =~ /^cms2ssh$/) {
405 pb_cms2build();
406 pb_build2ssh();
407} elsif ($action =~ /^pkg2ssh$/) {
408 pb_pkg2ssh();
409} elsif ($action =~ /^build2ve$/) {
410 pb_build2v("ve");
411} elsif ($action =~ /^build2vm$/) {
412 pb_build2v("vm");
413} elsif ($action =~ /^cms2ve$/) {
414 pb_cms2build();
415 pb_build2v("ve");
416} elsif ($action =~ /^cms2vm$/) {
417 pb_cms2build();
418 pb_build2v("vm");
419} elsif ($action =~ /^launchvm$/) {
420 pb_launchv("vm",$ENV{'PBV'},0);
421} elsif ($action =~ /^launchve$/) {
422 pb_launchv("ve",$ENV{'PBV'},0);
423} elsif ($action =~ /^script2vm$/) {
424 pb_script2v($pbscript,"vm");
425} elsif ($action =~ /^script2ve$/) {
426 pb_script2v($pbscript,"ve");
427} elsif ($action =~ /^newver$/) {
428 pb_newver();
429} elsif ($action =~ /^newve$/) {
430 pb_launchv("ve",$ENV{'PBV'},1);
431} elsif ($action =~ /^newvm$/) {
432 pb_launchv("vm",$ENV{'PBV'},1);
433} elsif ($action =~ /^setupve$/) {
434 my $pbscript = pb_setup_v("ve");
435 # 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 print SCRIPT $_;
1378 }
1379 close(PBD);
1380 last;
1381 }
1382}
1383close(SCRIPT);
1384chmod 0755,"$pbscript";
1385return($pbscript);
1386}
1387
1388sub pb_install_deps {
1389
1390my $SCRIPT = shift;
1391
1392print {$SCRIPT} << 'EOF';
1393# We need to have that pb_distro_init function
1394# Get it from Project-Builder::Distribution
1395my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init();
1396print "distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n";
1397
1398# Get and install pb
1399if ( $ddir eq "fedora" ) {
1400 system "yum clean all";
1401 #system "yum update -y";
1402 my $arch=`uname -m`;
1403 my $opt = "";
1404 chomp($arch);
1405 if ($arch eq "x86_64") {
1406 $opt="--exclude=*.i?86";
1407 }
1408
1409 system "yum -y $opt install rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker";
1410} 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"))) {
1411 # Suppose pkg are installed already
1412 system "rpm -e lsb 2>&1 > /dev/null";
1413 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 .. ";
1414} elsif ($ddir eq "suse") {
1415 # New OpenSuSE
1416 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";
1417} elsif ( $dfam eq "md" ) {
1418 system "urpmi.update -a ; urpmi --auto rpm-build wget sudo patch ntp-client perl-DateManip";
1419} elsif ( $dfam eq "du" ) {
1420 if (( $dver eq "3.1" ) && ($ddir eq "debian")) {
1421 #system "apt-get update";
1422 system "apt-get -y install wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libdate-manip-perl";
1423 } else {
1424 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";
1425 }
1426} elsif ( $dfam eq "gen" ) {
1427 system "emerge -u system ; emerge wget sudo ntp DateManip";
1428} else {
1429 print "No pkg to install\n";
1430}
1431EOF
1432}
1433
1434# Return the SSH key file to use
1435# Potentially create it if needed
1436
1437sub pb_ssh_get {
1438
1439my $create = shift || 0; # Do not create keys by default
1440
1441# Check the SSH environment
1442my $keyfile = undef;
1443
1444# We have specific keys by default
1445$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa";
1446if (!(-e $keyfile) && ($create eq 1)) {
1447 pb_system("ssh-keygen -q -b 1024 -N '' -f $keyfile -t dsa","Generating SSH keys for pb");
1448}
1449
1450$keyfile = "$ENV{'HOME'}/.ssh/id_rsa" if (-s "$ENV{'HOME'}/.ssh/id_rsa");
1451$keyfile = "$ENV{'HOME'}/.ssh/id_dsa" if (-s "$ENV{'HOME'}/.ssh/id_dsa");
1452$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa" if (-s "$ENV{'HOME'}/.ssh/pb_dsa");
1453die "Unable to find your public ssh key under $keyfile" if (not defined $keyfile);
1454return($keyfile);
1455}
1456
1457
1458# Returns the pid of a running VM command using a specific VM file
1459sub pb_check_ps {
1460 my $vmcmd = shift;
1461 my $vmm = shift;
1462 my $vmexist = 0; # FALSE by default
1463
1464 open(PS, "ps auxhww|") || die "Unable to call ps";
1465 while (<PS>) {
1466 next if (! /$vmcmd/);
1467 next if (! /$vmm/);
1468 my ($void1, $void2);
1469 ($void1, $vmexist, $void2) = split(/ +/);
1470 last;
1471 }
1472 return($vmexist);
1473}
1474
1475
1476sub pb_extract_build_files {
1477
1478my $src=shift;
1479my $dir=shift;
1480my $ddir=shift;
1481my @files;
1482
1483if ($src =~ /tar\.gz$/) {
1484 pb_system("tar xfpz $src $dir","Extracting build files");
1485} elsif ($src =~ /tar\.bz2$/) {
1486 pb_system("tar xfpj $src $dir","Extracting build files");
1487} else {
1488 die "Unknown compression algorithm for $src";
1489}
1490opendir(DIR,"$dir") || die "Unable to open directory $dir";
1491foreach my $f (readdir(DIR)) {
1492 next if ($f =~ /^\./);
1493 move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
1494 pb_log(2,"mv $dir/$f $ddir\n");
1495 push @files,"$ddir/$f";
1496}
1497closedir(DIR);
1498# Not enough but still a first cleanup
1499pb_rm_rf("$dir");
1500return(@files);
1501}
1502
1503sub pb_list_bfiles {
1504
1505my $dir = shift;
1506my $pbpkg = shift;
1507my $bfiles = shift;
1508my $pkgfiles = shift;
1509my $supfiles = shift;
1510
1511opendir(BDIR,"$dir") || die "Unable to open dir $dir: $!";
1512foreach my $f (readdir(BDIR)) {
1513 next if ($f =~ /^\./);
1514 $bfiles->{$f} = "$dir/$f";
1515 $bfiles->{$f} =~ s~$ENV{'PBROOTDIR'}~~;
1516 if (defined $supfiles->{$pbpkg}) {
1517 $pkgfiles->{$f} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/);
1518 }
1519}
1520closedir(BDIR);
1521}
1522
1523sub pb_syntax {
1524
1525my $exit_status = shift || -1;
1526my $verbose_level = shift || 0;
1527
1528my $filehandle = \*STDERR;
1529
1530$filehandle = \*STDOUT if ($exit_status == 0);
1531
1532pod2usage( { -message => "pb (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n",
1533 -exitval => $exit_status ,
1534 -verbose => $verbose_level,
1535 -output => $filehandle } );
1536}
Note: See TracBrowser for help on using the repository browser.