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

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

setupvm seems better now

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