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

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