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

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

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

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