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

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