source: devel/pb/bin/pb @ 1542

Last change on this file since 1542 was 1542, checked in by bruno, 7 years ago
  • pb: Add documentation for newve and setupve; fix bug in build2pkg documentation (Eric Anderson)
  • Property svn:executable set to *
File size: 139.6 KB
RevLine 
[5]1#!/usr/bin/perl -w
2#
3# Project Builder main application
4#
5# $Id$
6#
[1248]7# Copyright B. Cornec 2007-2011
[5]8# Provided under the GPL v2
9
[22]10# Syntax: see at end
[9]11
[18]12use strict 'vars';
[1107]13
14# The modules mentioned here are required by pb when used both
[1176]15# locally or inside a VE/VM/RM
[1107]16# Additional required modules only used locally are called with a require
17# in their respective section
[331]18use Getopt::Long qw(:config auto_abbrev no_ignore_case);
[9]19use Data::Dumper;
20use English;
[16]21use File::Basename;
[26]22use File::Copy;
[395]23use File::stat;
24use File::Temp qw(tempdir);
[872]25use File::Find;
[547]26use Time::localtime qw(localtime);
[13]27use POSIX qw(strftime);
[17]28use lib qw (lib);
[329]29use ProjectBuilder::Version;
[318]30use ProjectBuilder::Base;
[512]31use ProjectBuilder::Display;
[405]32use ProjectBuilder::Conf;
33use ProjectBuilder::Distribution;
[1469]34use ProjectBuilder::VCS;
[405]35use ProjectBuilder::CMS;
[416]36use ProjectBuilder::Env;
[405]37use ProjectBuilder::Filter;
[473]38use ProjectBuilder::Changelog;
[1348]39use ProjectBuilder::VE;
[473]40
[397]41# Global variables
[1537]42$Global::pb_stop_on_error = 1;
[5]43my %opts;                   # CLI Options
[9]44my $action;                 # action to realize
[320]45my $test = "FALSE";         # Not used
[748]46my $pbforce = 0;            # Force VE/VM rebuild
[968]47my $pbsnap = 0;             # Do not use snapshot mode for VM/VE by default
[1425]48my $pbkeep = 0;             # keep temporary directory at the end
[320]49my $option = "";            # Not used
50my @pkgs;                   # list of packages
[95]51my $pbtag;                  # Global Tag variable
52my $pbver;                  # Global Version variable
[141]53my $pbscript;               # Name of the script
[77]54my %pbver;                  # per package
55my %pbtag;                  # per package
[53]56my $pbrev;                  # Global REVISION variable
[1176]57my $pbaccount;              # Login to use to connect to the VM/RM
[1401]58my $pbtarget = undef;       # Target os-ver-arch you want to build for
[1176]59my $pbport;                 # Port to use to connect to the VM/RM
[199]60my $newver;                 # New version to create
[792]61my $iso = undef;            # ISO image for the VM to create
[5]62
[320]63my @date = pb_get_date();
64my $pbdate = strftime("%Y-%m-%d", @date);
[5]65
[331]66=pod
67
68=head1 NAME
69
70pb, aka project-builder.org - builds packages for your projects
71
72=head1 DESCRIPTION
73
74pb helps you build various packages directly from your project sources.
75Those sources could be handled by a CMS (Configuration Management System)
[748]76such as Subversion, CVS, Git, Mercurial... or being a simple reference to a compressed tar file.
[331]77It's based on a set of configuration files, a set of provided macros to help
78you keeping build files as generic as possible. For example, a single .spec
79file should be required to generate for all rpm based distributions, even
80if you could also have multiple .spec files if required.
81
82=head1 SYNOPSIS
83
[1401]84pb [-vhSq][-r pbroot][-p project][[-s script -a account -P port][-t [os-ver-arch]][-m os-ver-arch[,...]]][-g][-i iso] <action> [<pkg1> ...]
[331]85
[1401]86pb [--verbose][--help][--man][--quiet][--snapshot][--revision pbroot][--project project][[--script script --account account --port port][--target [os-ver-arch]][--machine os-ver-arch[,...]]][--nographic][--iso iso][--rebuild] <action> [<pkg1> ...]
[331]87
88=head1 OPTIONS
89
90=over 4
91
92=item B<-v|--verbose>
93
94Print a brief help message and exits.
95
96=item B<-q|--quiet>
97
98Do not print any output.
99
100=item B<-h|--help>
101
102Print a brief help message and exits.
103
[748]104=item B<-S|--snapshot>
105
106Use the snapshot mode of VMs or VEs
107
[331]108=item B<--man>
109
110Prints the manual page and exits.
111
[1120]112=item B<-t|--target os-ver-arch>
[331]113
[1120]114Name of the target system you want to build for.
115All if none precised.
116
117=item B<-m|--machine os-ver-arch[,os-ver-arch,...]>
118
[1176]119Name of the Virtual Machines (VM), Virtual Environments (VE) or Remote Machines (RM)
120you want to build on (coma separated).
[331]121All if none precised (or use the env variable PBV).
122
123=item B<-s|--script script>
124
[1176]125Name of the script you want to execute on the related VMs/VEs/RMs.
[331]126
[1158]127=item B<-g|--nographic>
[1124]128
129Do not launch VMs in graphical mode.
130
[331]131=item B<-i|--iso iso_image>
132
133Name of the ISO image of the distribution you want to install on the related VMs.
134
135=item B<-a|--account account>
136
[1176]137Name of the account to use to connect on the related VMs/RMs.
[331]138
139=item B<-P|--port port_number>
140
[1176]141Port number to use to connect on the related VMs/RMs.";
[331]142
143=item B<-p|--project project_name>
144
145Name of the project you're working on (or use the env variable PBPROJ)
146
147=item B<-r|--revision revision>
148
149Path Name of the project revision under the CMS (or use the env variable PBROOT)
150
151=item B<-V|--version new_version>
152
153New version of the project to create based on the current one.
154
[1425]155=item B<-k|--keep>
156
157Keep the temporary dir where files have been created in or der to help debug
158
[1386]159=item B<--rebuild>
160
161Only valid with the checkssh action, it alllows to automatically relaunch the build of the failed packages
162
[1537]163=item B<--no-stop-on-error>
164
165Continue through errors with best effort.
166
[331]167=back
168
169=head1 ARGUMENTS
170
171<action> can be:
172
173=over 4
174
[1097]175=item B<sbx2build>
176
177Create tar files for the project under your CMS.
178Current state of the exported content is taken.
179CMS supported are SVN, SVK, CVS, Git and Mercurial
180parameters are packages to build
181if not using default list
182
[331]183=item B<cms2build>
184
185Create tar files for the project under your CMS.
[1097]186Current state of the CMS is taken.
187CMS supported are SVN, SVK, CVS, Git and Mercurial
[331]188parameters are packages to build
189if not using default list
190
191=item B<build2pkg>
192
193Create packages for your running distribution
194
195=item B<cms2pkg>
196
197cms2build + build2pkg
198
[1097]199=item B<sbx2pkg>
200
201sbx2build + build2pkg
202
[331]203=item B<build2ssh>
204
205Send the tar files to a SSH host
206
[1097]207=item B<sbx2ssh>
208
209sbx2build + build2ssh
210
[331]211=item B<cms2ssh>
212
213cms2build + build2ssh
214
215=item B<pkg2ssh>
216
217Send the packages built to a SSH host
218
219=item B<build2vm>
220
221Create packages in VMs, launching them if needed
222and send those packages to a SSH host once built
[1176]223VM type supported are QEMU and KVM
[331]224
225=item B<build2ve>
226
227Create packages in VEs, creating it if needed
228and send those packages to a SSH host once built
229
[1176]230=item B<build2rm>
231
232Create packages in RMs, which should pre-exist,
233and send those packages to a SSH host once built
234RM means Remote Machine, and could be a physical or Virtual one.
235This is one buildfarm integration for pb.
236
[1097]237=item B<sbx2vm>
238
239sbx2build + build2vm
240
241=item B<sbx2ve>
242
243sbx2build + build2ve
244
[1176]245=item B<sbx2rm>
246
247sbx2build + build2rm
248
[331]249=item B<cms2vm>
250
251cms2build + build2vm
252
253=item B<cms2ve>
254
255cms2build + build2ve
256
[1176]257=item B<cms2rm>
258
259cms2build + build2rm
260
[331]261=item B<launchvm>
262
263Launch one virtual machine
264
265=item B<launchve>
266
267Launch one virtual environment
268
269=item B<script2vm>
270
271Launch one virtual machine if needed
272and executes a script on it
273
274=item B<script2ve>
275
276Execute a script in a virtual environment
277
[1176]278=item B<script2rm>
279
280Execute a script on a remote machine
281
[331]282=item B<newvm>
283
284Create a new virtual machine
285
286=item B<newve>
287
288Create a new virtual environment
289
[346]290=item B<setupvm>
291
292Setup a virtual machine for pb usage
293
294=item B<setupve>
295
296Setup a virtual environment for pb usage
297
[1176]298=item B<setuprm>
299
300Setup a remote machine for pb usage
301
[1140]302=item B<sbx2setupvm>
303
304Setup a virtual machine for pb usage using the sandbox version of pb instead of the latest stable
305Reserved to dev team.
306
307=item B<sbx2setupve>
308
309Setup a virtual environment for pb usage using the sandbox version of pb instead of the latest stable
310Reserved to dev team.
311
[1176]312=item B<sbx2setuprm>
313
314Setup a remote machine for pb usage using the sandbox version of pb instead of the latest stable
315Reserved to dev team.
316
[748]317=item B<snapvm>
318
319Snapshot a virtual machine for pb usage
320
321=item B<snapve>
322
323Snapshot a virtual environment for pb usage
324
[1111]325=item B<updatevm>
326
327Update the distribution in the virtual machine
328
329=item B<updateve>
330
331Update the distribution in the virtual environment
332
[1176]333=item B<updaterm>
334
335Update the distribution in the remote machine
336
[783]337=item B<test2pkg>
338
339Test a package locally
340
[772]341=item B<test2vm>
342
343Test a package in a virtual machine
344
345=item B<test2ve>
346
347Test a package in a virtual environment
348
[1176]349=item B<test2rm>
350
351Test a package in a remote machine
352
[1386]353=item B<checkssh>
354
355Check the delivery of the packages on the repository
356
[331]357=item B<newver>
358
359Create a new version of the project derived
360from the current one
361
362=item B<newproj>
363
364Create a new project and a template set of
365configuration files under pbconf
366
[471]367=item B<announce>
368
369Announce the availability of the project through various means
370
[1117]371=item B<sbx2webssh>
[557]372
[1117]373Create tar files for the website under your CMS.
374Current state of the exported content is taken.
375Deliver the content to the target server using ssh from the exported dir.
[557]376
[1117]377=item B<cms2webssh>
378
379Create tar files for the website from your CMS.
380Deliver the content to the target server using ssh from the DVCS.
381
382=item B<sbx2webpkg>
383
384Create tar files for the website under your CMS.
385Current state of the exported content is taken.
386
387=item B<cms2webpkg>
388
389Create tar files for the website under your CMS.
390
[1495]391=item B<getconf>
392
393Print the full configuration parameters as found in the various configuration files. help to debug conf issues.
394
[739]395=item B<clean>
396
397Purge the build and delivery directories related to the current project
398
[1392]399=item B<cleanssh>
400
401Purge the ssh server of its packages (only for testver and test packages)
402
403=back
404
[331]405<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).
406
407=head1 WEB SITES
408
409The 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/>.
410
411=head1 USER MAILING LIST
412
413None exists for the moment.
414
415=head1 CONFIGURATION FILES
416
417Each pb user may have a configuration in F<$HOME/.pbrc>. The values in this file may overwrite any other configuration file value.
418
419Here is an example of such a configuration file:
420
421 #
422 # Define for each project the URL of its pbconf repository
423 # No default option allowed here as they need to be all different
424 #
425 # URL of the pbconf content
426 # This is the format of a classical URL with the extension of additional schema such as
427 # svn+ssh, cvs+ssh, ...
428 #
429 pbconfurl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe/pbconf
430
431 # This is normaly defined in the project's configuration file
432 # Url of the project
433 #
434 pburl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe
435 
436 # All these URLs needs to be defined here as the are the entry point
437 # for how to build packages for the project
438 #
439 pbconfurl pb = svn+ssh://svn.project-builder.org/mondo/svn/pb/pbconf
440 pbconfurl mondorescue = svn+ssh://svn.project-builder.org/mondo/svn/project-builder/mondorescue/pbconf
441 pbconfurl collectl = svn+ssh://bruno@svn.mondorescue.org/mondo/svn/project-builder/collectl/pbconf
442 pbconfurl netperf = svn+ssh://svn.mondorescue.org/mondo/svn/project-builder/netperf/pbconf
443 
444 # Under that dir will take place everything related to pb
445 # If you want to use VMs/chroot/..., then use $ENV{'HOME'} to make it portable
446 # to your VMs/chroot/...
447 # if not defined then /var/cache
448 pbdefdir default = $ENV{'HOME'}/project-builder
449 pbdefdir pb = $ENV{'HOME'}
450 pbdefdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
451 pbdefdir mondorescue = $ENV{'HOME'}/mondo/svn
452 
453 # pbconfdir points to the directory where the CMS content of the pbconfurl is checked out
454 # If not defined, pbconfdir is under pbdefdir/pbproj/pbconf
455 pbconfdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs/pbconf
456 pbconfdir mondorescue = $ENV{'HOME'}/mondo/svn/pbconf
457 
458 # pbdir points to the directory where the CMS content of the pburl is checked out
459 # If not defined, pbdir is under pbdefdir/pbproj
460 # Only defined if we have access to the dev of the project
461 pbdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
462 pbdir mondorescue = $ENV{'HOME'}/mondo/svn
463 
464 # -daemonize doesn't work with qemu 0.8.2
465 vmopt default = -m 384
466
[1537]467=head1 COMMAND DETAILS
468
469=head2 newproj
470
471The newproj command creates a new project-builder project.  To run this command you first need to define two variables in your ~/.pbrc file:
472
473 pbconfurl I<project> = file:///home/anderse/.git/project-builder-config/I<project>
474 pbdefdir default = $ENV{HOME}/cache-project-builder
475
476The first line defines the version controlled configuration information and the second defines the root directory for project-builder to use.
477
478You can then run the command:
479
480 % pb -p I<$project> -r I<$version> newproj
481
482to create the new project. Running the newproj command will then generate the file $pbdefdir/$project/pbconf/$version/$project.pb.  You will need to edit that file in order to run any of the later commands.
483
484=head2 cms2build
485
486The cms2build command takes your files from the content management system and makes the two tar files that are necessary for building files. Before running this command, you need to run the newproj command, and edit the $project.pb configuration file. In particular, you need to set the pburl, pbrepo, pbwf, pbpackager, projver, projtag, testver, deliver, and defpkgdir lines as described in the configuration file. Then you can run a command like:
487
488 % pb -p $project -r $version cms2build
489
490To create the $pbdefdir/$project/delivery/$project-$version.{,pbconf}.tar.gz files, the $version-$projtag.pb and pbrc files in the same directory.
491
492=head2 build2pkg
493
[1542]494The build2pkg command takes the tar files created in the cms2build step and attempts to build the binary packages for your current operating system. In order for this step to work, you may need to edit the files in one of the $pbdefdir/$project/pbconf/$version/$project/{deb,rpm,pkg} directories. Those files will be used to try to build your package. Note that if you change those files, you need to re-run the cms2build step. Then you can run a command like:
[1537]495
[1542]496 % pb -p $project -r $version build2pkg
[1537]497
[1542]498To create the files in $project/build that comprise your binary package(s).
499
500=head2 newve
501 
502The newve command creates a new virtual environment, i.e. a chrooted OS for building packages. Using a virtual environment is an efficient way to build packages on a related set of operating systems. The OS's have to be related because the kernel will be shared.  Steps:
503
504=over 4
505
506=item Update ~/.pbrc
507
508Update your ~/.pbrc file to specify the vepath, velist, velogin, and vetype variables, e.g.:
509
510 vepath default = $ENV{HOME}/cache-project-builder/chroot
511 velist default = debian-6.0-i386
512 velogin default = pb
513 vetype default = chroot
514
515You may also choose to specify a mirror for the OS packages, and optionally http/ftp proxies.  You can specify the proxies either through environment variables ($http_proxy/$ftp_proxy) or in the configuration file. The configuration file will be used if no corresponding environment variable has been set. For example, for debian and with a local squid proxy:
516
517 rbsmirrorsrv debian = http://mirrors1.kernel.org/debian/
518 http_proxy default = http://localhost:3128/
519 ftp_proxy default = http://localhost:3128/
520
521=item Run the cms2build command
522
523If you have deleted your $package/delivery directory, re-run the cms2build command as in the earlier step. This step is necessary to generate the I<package>/delivery/pbrc file.
524
525=item Create the new virtual environment
526
527Initialize the new operating system. This step will install the core OS packages for the virtual environment, e.g.:
528
529 % pb -v -p $project -m debian-6.0-i386 newve
530
531=back
532
533=head2 setupve
534
535The setupve command prepares a virtual environment for use by project builder. In particular it installs project-builder from the packages into the virtual environment. For example:
536
537 % pb -v -p $project -m debian-6.0-i386 setupve
538
539If you prefer to install the current SVN version of project builder, you can substitute the setupve option by the sbx2setupv one.
540
[331]541=head1 AUTHORS
542
543The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
544
545=head1 COPYRIGHT
546
547Project-Builder.org is distributed under the GPL v2.0 license
548described in the file C<COPYING> included with the distribution.
549
550=cut
551
552# ---------------------------------------------------------------------------
553
[75]554my ($projectbuilderver,$projectbuilderrev) = pb_version_init();
[974]555my $appname = "pb";
[331]556
[397]557# Initialize the syntax string
558
[974]559pb_syntax_init("$appname (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n");
[397]560
[331]561GetOptions("help|?|h" => \$opts{'h'}, 
562        "man" => \$opts{'man'},
563        "verbose|v+" => \$opts{'v'},
[748]564        "snapshot|S" => \$opts{'S'},
[331]565        "quiet|q" => \$opts{'q'},
566        "log-files|l=s" => \$opts{'l'},
567        "force|f" => \$opts{'f'},
568        "account|a=s" => \$opts{'a'},
569        "revision|r=s" => \$opts{'r'},
570        "script|s=s" => \$opts{'s'},
571        "machines|mock|m=s" => \$opts{'m'},
[1401]572        "target|t:s" => \$opts{'t'},
[1158]573        "nographic|g" => \$opts{'g'},
[331]574        "port|P=i" => \$opts{'P'},
575        "project|p=s" => \$opts{'p'},
[1386]576        "rebuild" => \$opts{'rebuild'},
[331]577        "iso|i=s" => \$opts{'i'},
[815]578        "version|V=s" => \$opts{'V'},
[1425]579        "keep|k" => \$opts{'k'},
[1537]580        "stop-on-error!" => \$Global::pb_stop_on_error,
[331]581) || pb_syntax(-1,0);
582
[21]583if (defined $opts{'h'}) {
[331]584    pb_syntax(0,1);
[21]585}
[331]586if (defined $opts{'man'}) {
587    pb_syntax(0,2);
588}
[21]589if (defined $opts{'v'}) {
[495]590    $pbdebug = $opts{'v'};
[21]591}
[320]592if (defined $opts{'f'}) {
[748]593    $pbforce=1;
[320]594}
[21]595if (defined $opts{'q'}) {
[495]596    $pbdebug=-1;
[21]597}
[748]598if (defined $opts{'S'}) {
599    $pbsnap=1;
600}
[1425]601if (defined $opts{'k'}) {
602    $pbkeep=1;
603}
[22]604if (defined $opts{'l'}) {
[495]605    open(pbLOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!";
606    $pbLOG = \*pbLOG;
607    $pbdebug = 0  if ($pbdebug == -1);
[22]608    }
[495]609pb_log_init($pbdebug, $pbLOG);
610pb_display_init("text","");
[315]611
[67]612# Handle root of the project if defined
613if (defined $opts{'r'}) {
[340]614    $ENV{'PBROOTDIR'} = $opts{'r'};
[67]615}
[91]616# Handle virtual machines if any
617if (defined $opts{'m'}) {
[320]618    $ENV{'PBV'} = $opts{'m'};
[91]619}
[141]620if (defined $opts{'s'}) {
621    $pbscript = $opts{'s'};
622}
[152]623if (defined $opts{'a'}) {
624    $pbaccount = $opts{'a'};
[347]625    die "option -a requires a -s script option" if (not defined $pbscript);
[152]626}
[162]627if (defined $opts{'P'}) {
628    $pbport = $opts{'P'};
629}
[199]630if (defined $opts{'V'}) {
631    $newver = $opts{'V'};
632}
[262]633if (defined $opts{'i'}) {
634    $iso = $opts{'i'};
635}
[1120]636if (defined $opts{'t'}) {
637    $pbtarget = $opts{'t'};
638}
[108]639
640# Get Action
641$action = shift @ARGV;
[331]642die pb_syntax(-1,1) if (not defined $action);
[108]643
[314]644my ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir);
[273]645my $pbinit = undef;
646$pbinit = 1 if ($action =~ /^newproj$/);
[108]647
[59]648# Handles project name if any
[108]649# And get global params
[1425]650($filteredfiles, $supfiles, $defpkgdir, $extpkgdir) = pb_env_init($opts{'p'},$pbinit,$action,$pbkeep);
[59]651
[982]652#
653# Check for command requirements
654#
[1126]655my ($req,$opt,$pbpara) = pb_conf_get_if("oscmd","oscmdopt","pbparallel");
[1128]656pb_check_requirements($req,$opt,$appname);
[982]657
[1125]658#
659# Check if we can launch some actions in // with Parallel::ForkManager
660#
[1126]661my $pbparallel = $pbpara->{$appname} if (defined $pbpara);
662if (not defined $pbparallel) {
663    eval
664    {
665        require Sys::CPU;
666        Sys::CPU->import();
667    };
668    if ($@) {
669        # Sys::CPU not found, defaulting to 1
[1153]670        pb_log(1,"ADVISE: Install Sys::CPU to benefit from automatic parallelism optimization.\nOr use pbparallel in your pb.conf file\nOnly 1 process at a time for the moment\n");
[1126]671        $pbparallel = 1;
672    } else {
673        # Using the number of cores
674        $pbparallel = Sys::CPU::cpu_count();
[1153]675        pb_log(1,"Using parallel mode with $pbparallel processes\n");
[1126]676    }
677}
678
[1125]679eval
680{
681    require Parallel::ForkManager;
682    Parallel::ForkManager->import();
683};
684# Parallel::ForkManager not found so no // actions
685if ($@) {
686    $pbparallel = undef;
[1153]687    pb_log(1,"ADVISE: Install Parallel::ForkManager to benefit from automatic parallelism optimization.\nOnly 1 process at a time for the moment\n");
[1125]688}
689
[315]690pb_log(0,"Project: $ENV{'PBPROJ'}\n");
691pb_log(0,"Action: $action\n");
[9]692
693# Act depending on action
694if ($action =~ /^cms2build$/) {
[1097]695    pb_cms2build("CMS");
696} elsif ($action =~ /^sbx2build$/) {
697    pb_cms2build("SandBox");
[77]698} elsif ($action =~ /^build2pkg$/) {
699    pb_build2pkg();
700} elsif ($action =~ /^cms2pkg$/) {
[1097]701    pb_cms2build("CMS");
[77]702    pb_build2pkg();
[1097]703} elsif ($action =~ /^sbx2pkg$/) {
704    pb_cms2build("SandBox");
705    pb_build2pkg();
[88]706} elsif ($action =~ /^build2ssh$/) {
707    pb_build2ssh();
[220]708} elsif ($action =~ /^cms2ssh$/) {
[1097]709    pb_cms2build("CMS");
[220]710    pb_build2ssh();
[1102]711} elsif ($action =~ /^sbx2ssh$/) {
[1097]712    pb_cms2build("SandBox");
713    pb_build2ssh();
[88]714} elsif ($action =~ /^pkg2ssh$/) {
715    pb_pkg2ssh();
[1176]716} elsif ($action =~ /^build2rm$/) {
717    pb_build2v("rm","build");
[320]718} elsif ($action =~ /^build2ve$/) {
[772]719    pb_build2v("ve","build");
[91]720} elsif ($action =~ /^build2vm$/) {
[772]721    pb_build2v("vm","build");
[1176]722} elsif ($action =~ /^cms2rm$/) {
723    pb_cms2build("CMS");
724    pb_build2v("rm","build");
[320]725} elsif ($action =~ /^cms2ve$/) {
[1097]726    pb_cms2build("CMS");
[772]727    pb_build2v("ve","build");
[1176]728} elsif ($action =~ /^sbx2rm$/) {
729    pb_cms2build("SandBox");
730    pb_build2v("rm","build");
[1097]731} elsif ($action =~ /^sbx2ve$/) {
732    pb_cms2build("SandBox");
733    pb_build2v("ve","build");
[91]734} elsif ($action =~ /^cms2vm$/) {
[1097]735    pb_cms2build("CMS");
[772]736    pb_build2v("vm","build");
[1097]737} elsif ($action =~ /^sbx2vm$/) {
738    pb_cms2build("SandBox");
739    pb_build2v("vm","build");
[141]740} elsif ($action =~ /^launchvm$/) {
[320]741    pb_launchv("vm",$ENV{'PBV'},0);
742} elsif ($action =~ /^launchve$/) {
743    pb_launchv("ve",$ENV{'PBV'},0);
[142]744} elsif ($action =~ /^script2vm$/) {
[320]745    pb_script2v($pbscript,"vm");
746} elsif ($action =~ /^script2ve$/) {
747    pb_script2v($pbscript,"ve");
[1176]748} elsif ($action =~ /^script2rm$/) {
749    pb_script2v($pbscript,"rm");
[199]750} elsif ($action =~ /^newver$/) {
751    pb_newver();
[320]752} elsif ($action =~ /^newve$/) {
753    pb_launchv("ve",$ENV{'PBV'},1);
[262]754} elsif ($action =~ /^newvm$/) {
[320]755    pb_launchv("vm",$ENV{'PBV'},1);
[909]756    pb_log(0, "Please ensure that sshd is running in your VM by default\n");
757    pb_log(0, "and that it allows remote root login (PermitRootLogin yes in /etc/ssh/sshd_config)\n");
[1105]758    pb_log(0, "Also ensure that network is up, firewalling correctly configured\n");
759    pb_log(0, "and perl, sudo, ntpdate and scp/ssh installed\n");
[1072]760    pb_log(0, "You should then be able to login with ssh -p VMPORT root\@localhost (if VM started with pb)\n");
[1176]761} elsif ($action =~ /^setuprm$/) {
762    pb_setup2v("rm");
[346]763} elsif ($action =~ /^setupve$/) {
[772]764    pb_setup2v("ve");
[346]765} elsif ($action =~ /^setupvm$/) {
[772]766    pb_setup2v("vm");
[1176]767} elsif ($action =~ /^sbx2setuprm$/) {
768    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
769    pb_cms2build("SandBox");
770    pb_setup2v("rm","SandBox");
[1140]771} elsif ($action =~ /^sbx2setupve$/) {
772    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
773    pb_cms2build("SandBox");
774    pb_setup2v("ve","SandBox");
775} elsif ($action =~ /^sbx2setupvm$/) {
776    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
777    pb_cms2build("SandBox");
778    pb_setup2v("vm","SandBox");
[1176]779} elsif ($action =~ /^updaterm$/) {
780    pb_update2v("rm");
[1111]781} elsif ($action =~ /^updateve$/) {
782    pb_update2v("ve");
783} elsif ($action =~ /^updatevm$/) {
784    pb_update2v("vm");
[748]785} elsif ($action =~ /^snapve$/) {
[772]786    pb_snap2v("ve");
[748]787} elsif ($action =~ /^snapvm$/) {
[772]788    pb_snap2v("vm");
[783]789} elsif ($action =~ /^test2pkg$/) {
790    pb_test2pkg();
[1176]791} elsif ($action =~ /^test2rm$/) {
792    pb_build2v("rm","test");
[772]793} elsif ($action =~ /^test2ve$/) {
794    pb_build2v("ve","test");
795} elsif ($action =~ /^test2vm$/) {
796    pb_build2v("vm","test");
[273]797} elsif ($action =~ /^newproj$/) {
798    # Nothing to do - already done in pb_env_init
[1495]799} elsif ($action =~ /^getconf$/) {
800    my $pbos = pb_distro_get_context();
801    pb_conf_print();
[106]802} elsif ($action =~ /^clean$/) {
[739]803    pb_clean();
[471]804} elsif ($action =~ /^announce$/) {
[498]805    # For announce only. Require avoids the systematic load of these modules
806    require DBI;
[557]807    require DBD::SQLite;
[498]808
[1386]809    pb_announce("Announce");
[1392]810} elsif ($action =~ /^cleanssh$/) {
811    pb_announce("Clean");
[1386]812} elsif ($action =~ /^checkssh$/) {
813    pb_announce("Check");
[1117]814} elsif ($action =~ /^sbx2webpkg$/) {
[547]815    require DBI;
[557]816    require DBD::SQLite;
[547]817
[1117]818    pb_cms2build("SandBox","Web");
819} elsif ($action =~ /^sbx2webssh$/) {
820    require DBI;
821    require DBD::SQLite;
822
823    pb_cms2build("SandBox","Web");
[556]824    pb_send2target("Web");
[1117]825} elsif ($action =~ /^cms2webpkg$/) {
826    require DBI;
827    require DBD::SQLite;
828
829    pb_cms2build("CMS","Web");
830} elsif ($action =~ /^cms2webssh$/) {
831    require DBI;
832    require DBD::SQLite;
833
834    pb_cms2build("CMS","Web");
835    pb_send2target("Web");
[77]836} else {
[315]837    pb_log(0,"\'$action\' is not available\n");
[331]838    pb_syntax(-2,1);
[77]839}
840
841sub pb_cms2build {
842
[556]843    my $param = shift || undef;
[1117]844    my $web = shift || undef;
[556]845
846    my $pkg;
847    my @pkgs;
[557]848    my $webdir;
[556]849
[557]850    my %pkgs;
[1186]851    my $pb;             # Structure to store conf info
[557]852
[1117]853    die "pb_cms2build requires a parameter: SandBox or CMS" if (not defined $param);
[1097]854
[556]855    # If Website, then pkg is only the website
[1117]856    if (defined $web) {
[557]857        ($webdir) = pb_conf_get("webdir");
858        pb_log(2,"webdir: ".Dumper($webdir)."\n");
859        $pkgs[0] = $webdir->{$ENV{'PBPROJ'}};
[556]860        $extpkgdir = $webdir;
[557]861        pb_log(0,"Package: $pkgs[0]\n");
[556]862    } else {
863        $pkg = pb_cms_get_pkg($defpkgdir,$extpkgdir);
864        @pkgs = @$pkg;
865    }
866
[1097]867    my ($scheme, $uri) = pb_cms_init($pbinit,$param);
[331]868
[898]869    # We need 2 lines here
870    my ($pkgv, $pkgt, $testver) = pb_conf_get_if("pkgver","pkgtag","testver");
[174]871
[429]872    # declare packager and repo for filtering
873    my ($tmp1, $tmp2) = pb_conf_get("pbpackager","pbrepo");
874    $ENV{'PBPACKAGER'} = $tmp1->{$ENV{'PBPROJ'}};
875    $ENV{'PBREPO'} = $tmp2->{$ENV{'PBPROJ'}};
[1203]876    my ($delivery) = pb_conf_get_if("delivery");
877    $delivery->{$ENV{'PBPROJ'}} = "" if (not defined $delivery->{$ENV{'PBPROJ'}});
[174]878
[1432]879    # If we deal with a test dir, we want to keep the date in tar file and dir name
880    my $pbextdir = "";
881        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
882            $pbextdir = strftime("%Y%m%d%H%M%S", @date);
883    }
884
[27]885    foreach my $pbpkg (@pkgs) {
[115]886        $ENV{'PBPKG'} = $pbpkg;
[728]887
[98]888        if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) {
889            $pbver = $pkgv->{$pbpkg};
[9]890        } else {
[353]891            $pbver = $ENV{'PBPROJVER'};
[9]892        }
[1432]893        # If it's a test version, then tag == 0
[897]894        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
[1432]895            $pbtag = "0";
[728]896            $ENV{'PBPROJTAG'} = $pbtag;
897        } elsif ((defined $pkgt) && (defined $pkgt->{$pbpkg})) {
[98]898            $pbtag = $pkgt->{$pbpkg};
[9]899        } else {
[353]900            $pbtag = $ENV{'PBPROJTAG'};
[9]901        }
[95]902
[16]903        $pbrev = $ENV{'PBREVISION'};
[319]904        pb_log(0,"\n");
905        pb_log(0,"Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n");
[9]906        die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
[539]907
[1432]908        my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir";
[1173]909        # Create the structure if needed
910        pb_mkdir_p($dest);
[16]911        # Clean up dest if necessary. The export will recreate it
[74]912        pb_rm_rf($dest) if (-d $dest);
[9]913
914        # Export CMS tree for the concerned package to dest
915        # And generate some additional files
916        $OUTPUT_AUTOFLUSH=1;
[29]917
[9]918        # computes in which dir we have to work
[113]919        my $dir = $defpkgdir->{$pbpkg};
920        $dir = $extpkgdir->{$pbpkg} if (not defined $dir);
[1117]921        $dir = $webdir->{$ENV{'PBPROJ'}} if (defined $web);
922        die "Variable \$dir not defined. Please report to dev team with log of a verbose run and this info ".Dumper($webdir) if (not defined $dir);
[1260]923        pb_log(2,"def:".Dumper($defpkgdir)."ext: ".Dumper($extpkgdir)."dir: $dir\n");
[9]924
[537]925        # Exporting content from CMS
[1097]926        my $sourcedir = undef;
927        my $sourceuri = $uri;
928        if ($param eq "SandBox") {
929            # Point to the local instance
930            $sourcedir = "$ENV{'PBDIR'}/$dir";
931        } else {
932            # Get it from a subdir of the URI with same version as localy but different root
[1174]933            # Only if using a real CMS
934            my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
935            if (($scheme !~ /^file/) && ($scheme !~ /^(ht|f)tp/)) {
936                $sourceuri = "$ENV{'PBDIR'}/$dir"; 
[1260]937                $sourceuri =~ s|^$ENV{'PBPROJDIR'}/|$uri/|;
[1174]938            }
[1097]939        }
[1469]940        my $preserve = pb_vcs_export($sourceuri,$sourcedir,$dest);
[315]941
[435]942        # Generated fake content for test versions to speed up stuff
943        my $chglog;
[285]944
[448]945        # Get project info on authors and log file
[1185]946        # TODO: Make it CMS aware
[448]947        $chglog = "$ENV{'PBROOTDIR'}/$pbpkg/pbcl";
948        $chglog = "$ENV{'PBROOTDIR'}/pbcl" if (! -f $chglog);
949        $chglog = undef if (! -f $chglog);
[285]950
[1185]951        # TODO: Make it CMS aware
[448]952        my $authors = "$ENV{'PBROOTDIR'}/$pbpkg/pbauthors";
953        $authors = "$ENV{'PBROOTDIR'}/pbauthors" if (! -f $authors);
954        $authors = "/dev/null" if (! -f $authors);
[435]955
[448]956        # Extract cms log history and store it
957        if ((defined $chglog) && (! -f "$dest/NEWS")) {
958            pb_log(2,"Generating NEWS file from $chglog\n");
959            copy($chglog,"$dest/NEWS") || die "Unable to create $dest/NEWS";
[285]960        }
[448]961        pb_cms_log($scheme,"$ENV{'PBDIR'}/$dir",$dest,$chglog,$authors,$testver);
[29]962
[21]963        my %build;
[865]964        # We want to at least build for the underlying distro
[1120]965        # except if a target was given, in which case we only build for it
[1401]966        # if -t was passed without target then build for the native distro.
[1177]967        my $pbos = pb_distro_get_context($pbtarget);
[1282]968        my $tmpl = pb_get_distros($pbos,$pbtarget);
[1120]969
[1186]970        # Setup $pb structure to allow filtering later on, on files using that structure
971        $pb->{'tag'} = $pbtag;
972        $pb->{'rev'} = $pbrev;
973        $pb->{'ver'} = $pbver;
974        $pb->{'pkg'} = $pbpkg;
[1192]975        $pb->{'suf'} = $pbos->{'suffix'};
[1186]976        $pb->{'realpkg'} = $pbpkg;
977        $pb->{'date'} = $pbdate;
978        $pb->{'defpkgdir'} = $defpkgdir;
979        $pb->{'extpkgdir'} = $extpkgdir;
980        $pb->{'chglog'} = $chglog;
[1432]981        $pb->{'extdir'} = $pbextdir;
[1186]982        $pb->{'packager'} = $ENV{'PBPACKAGER'};
983        $pb->{'proj'} = $ENV{'PBPROJ'};
[1200]984        $pb->{'repo'} = "$ENV{'PBREPO'}/$delivery->{$ENV{'PBPROJ'}}";
[1186]985        $pb->{'patches'} = ();
986        $pb->{'sources'} = ();
[556]987   
[1185]988        my $tmpd = "$ENV{'PBTMP'}/cms.$$";
989        pb_mkdir_p($tmpd) if (defined $pbparallel);
990
991        # Get only all.pbf filter at this stage for pbinit
992        my $ptr = pb_get_filters($pbpkg);
993
[556]994        # Do not do that for website
[1117]995        if (not defined $web) {
[665]996            my %virt;
[1176]997            # De-duplicate similar VM/VE/RM
[556]998            foreach my $d (split(/,/,$tmpl)) {
[766]999                # skip ill-formatted vms (name-ver-arch)
1000                next if ($d !~ /-/);
[665]1001                $virt{$d} = $d;
1002            }
1003
[1125]1004            # Try to use // processing here
[1350]1005            my $pm = new Parallel::ForkManager($pbparallel) if (defined $pbparallel);
[1125]1006
[1189]1007            pb_log(0,"Preparing delivery ...\n");
[1177]1008            foreach my $v (keys %virt) {
[1125]1009                $pm->start and next if (defined $pbparallel);
[1177]1010
1011                # Distro context
1012                my $pbos = pb_distro_get_context($v);
[1207]1013   
[1186]1014                $pb->{'pbos'} = $pbos;
[1189]1015                $pb->{'suf'} = $pbos->{'suffix'};
[1186]1016                pb_log(3,"DEBUG: pb: ".Dumper($pb)."\n");
[1185]1017
1018                # Get all filters to apply
[1192]1019                $ptr = pb_get_filters($pbpkg,$pbos);
[1185]1020   
[556]1021                pb_log(2,"DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n");
1022   
1023                # We need to compute the real name of the package
[1177]1024                my $pbrealpkg = pb_cms_get_real_pkg($pbpkg,$pbos->{'type'});
[1186]1025                $pb->{'realpkg'} = $pbrealpkg;
[1177]1026                pb_log(1,"Virtual package $pbpkg has a real package name of $pbrealpkg on $pbos->{'name'}-$pbos->{'version'}\n") if ($pbrealpkg ne $pbpkg);
[556]1027   
1028                # Filter build files from the less precise up to the most with overloading
1029                # Filter all files found, keeping the name, and generating in dest
1030   
1031                # Find all build files first relatively to PBROOTDIR
1032                # Find also all specific files referenced in the .pb conf file
1033                my %bfiles = ();
1034                my %pkgfiles = ();
[1185]1035                # Used in Filter.pm by pb_filter_file
1036
[1363]1037                $build{$v} = "no";
[1185]1038                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'os'}") {
1039                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'os'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1040                    $build{$v} = "yes";
1041                } 
1042                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'type'}") {
[1177]1043                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'type'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1044                    $build{$v} = "yes";
1045                } 
1046                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'family'}") {
[1177]1047                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'family'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1048                    $build{$v} = "yes";
1049                } 
1050                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}") {
[1177]1051                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1052                    $build{$v} = "yes";
1053                } 
1054                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}") {
[1177]1055                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1056                    $build{$v} = "yes";
1057                } 
1058                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") {
[1177]1059                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
[1363]1060                    $build{$v} = "yes";
[500]1061                }
[1186]1062                pb_log(2,"DEBUG($v) bfiles: ".Dumper(\%bfiles)."\n");
[556]1063   
[1185]1064                if ($build{$v} ne "no") {
1065                    # Apply now all the filters on all the files concerned
1066                    # destination dir depends on the type of file
[556]1067                    # For patch support
[1185]1068                    # TODO: Make it CMS aware
[1186]1069                    $pb->{'patches'} = pb_list_sfiles("$ENV{'PBROOTDIR'}/$pbpkg/pbpatch", $pb->{'patches'}, $pbos, "$ENV{'PBROOTDIR'}/$pbpkg/pbextpatch");
1070                    pb_log(2,"DEBUG($v) patches: ".Dumper($pb->{'patches'})."\n");
[1185]1071                    # TODO: Make it CMS aware
[1186]1072                    $pb->{'sources'} = pb_list_sfiles("$ENV{'PBROOTDIR'}/$pbpkg/pbsrc", $pb->{'sources'}, $pbos, "$ENV{'PBROOTDIR'}/$pbpkg/pbextsrc");
1073                    pb_log(2,"DEBUG($v) sources: ".Dumper($pb->{'sources'})."\n");
[1185]1074   
[1186]1075                    if (defined $pb->{'patches'}->{$v}) {
[1185]1076                        # Filter potential patches (local + remote)
1077                        pb_mkdir_p("$dest/pbconf/$v/pbpatch");
[1367]1078                        # If Debian based distribution, then prepare what will be done at build time
1079                        my ($patchcmd,$patchopt);
1080                        if ($pbos->{'type'} eq "deb") {
1081                            ($patchcmd,$patchopt) = pb_distro_get_param($pbos,pb_conf_get_if("ospatchcmd","ospatchopt"));
1082                            open(SCRIPT,"> $dest/pbconf/$v/pbpatch/pbapplypatch") || die "Unable to create $dest/pbconf/$v/pbpatch/pbapplypatch";
1083                            print SCRIPT "#!/bin/bash\n";
1084                            print SCRIPT "set -x\n" if ($pbdebug gt 1);
1085                        }
[1186]1086                        foreach my $pf (split(/,/,$pb->{'patches'}->{$v})) {
[1185]1087                            my $pp = basename($pf);
[1469]1088                            pb_vcs_export($pf,undef,"$dest/pbconf/$v/pbpatch");
[1186]1089                            pb_filter_file_inplace($ptr,"$dest/pbconf/$v/pbpatch/$pp",$pb);
[1185]1090                            pb_system("gzip -9f $dest/pbconf/$v/pbpatch/$pp","","quiet");
[1367]1091                            if ($pbos->{'type'} eq "deb") {
1092                                # If Debian based distribution, then prepare what will be done at build time
1093                                # by applying the patches that will be available under the debian/patches dir
1094                                print SCRIPT "$patchcmd $patchopt \< debian/patches/$pp\n";
1095                            }
[1185]1096                        }
[1367]1097                        if ($pbos->{'type'} eq "deb") {
1098                            close(SCRIPT);
1099                            chmod 0755,"$dest/pbconf/$v/pbpatch/pbapplypatch";
1100                        }
1101                        #pb_system("cat $dest/pbconf/$v/pbpatch/pbapplypatch","APPLY","verbose");
[1185]1102                    }
[1186]1103                    if (defined $pb->{'sources'}->{$v}) {
[1185]1104                        pb_mkdir_p("$dest/pbconf/$v/pbsrc");
[1186]1105                        foreach my $pf (split(/,/,$pb->{'sources'}->{$v})) {
[1185]1106                            my $pp = basename($pf);
[1469]1107                            pb_vcs_export($pf,undef,"$dest/pbconf/$v/pbsrc");
[1186]1108                            pb_filter_file_inplace($ptr,"$dest/pbconf/$v/pbsrc/$pp",$pb);
[1185]1109                        }
1110                    }
[1186]1111                    # Filter build files at the end, as they depend on patches and sources
[1363]1112                    foreach my $f (keys %bfiles) {
1113                        pb_filter_file("$ENV{'PBROOTDIR'}/$bfiles{$f}",$ptr,"$dest/pbconf/$v/$f",$pb);
[1186]1114                    }
[1363]1115                    foreach my $f (keys %pkgfiles) {
1116                        pb_filter_file("$ENV{'PBROOTDIR'}/$pkgfiles{$f}",$ptr,"$dest/pbconf/$v/$f",$pb);
1117                    }
[556]1118                }
[1130]1119
[1185]1120                if (defined $pbparallel) {
1121                    # Communicate results back to parent
1122                    my $str = "";
1123                    $str .= "build $v = $build{$v}\n" if (defined $build{$v});
[1186]1124                    $str .= "patches $v = $pb->{'patches'}->{$v}\n" if (defined $pb->{'patches'}->{$v});
1125                    $str .= "sources $v = $pb->{'sources'}->{$v}\n" if (defined $pb->{'sources'}->{$v});
[1185]1126                    pb_set_content("$tmpd/$$","$str");
1127                    $pm->finish;
1128                }
[15]1129            }
[1185]1130            # In the parent, we need to get the result from the children
[1125]1131            $pm->wait_all_children if (defined $pbparallel);
[1185]1132            my $made = "";
1133            my %h = ();
1134            my %tmp;
[1186]1135            my %tmp2;
[1185]1136            my $pt;
1137            my $k;
1138
1139            foreach $k (<$tmpd/*>) {
1140                $made .= pb_get_content($k);
[556]1141            }
[1185]1142            pb_rm_rf($tmpd);
1143            pb_log(3,"MADE:\n$made");
[500]1144
[1185]1145            # Rebuild local hashes
1146            foreach $k (split(/\n/,$made)) {
1147                if ($k =~ /^\s*([A-z0-9-_]+)\s+([[A-z0-9-_.]+)\s*=\s*(.+)$/) {
1148                    $h{$1}->{$2}=$3;
1149                }
1150            }
[1186]1151            pb_log(2,"HASH: ".Dumper(%h));
[236]1152
[1185]1153            # Patches
1154            pb_log(0,"Delivered and compressed patches ");
1155            $pt = $h{'patches'};
[1186]1156            foreach $k (keys %$pt) {
1157                foreach my $v1 (split(/,/,$pt->{$k})) {
1158                    $tmp{$v1} = "";
1159                }
[1185]1160            }
[1186]1161            if (keys %tmp) {
1162                foreach $k (keys %tmp) {
1163                    pb_log(0,"$k ");
1164                }
1165            } else {
1166                pb_log(0,"N/A");
[1185]1167            }
1168            pb_log(0,"\n");
[236]1169
[1185]1170            # Sources
1171            pb_log(0,"Delivered additional sources ");
1172            $pt = $h{'sources'};
[1186]1173            foreach $k (keys %$pt) {
1174                foreach my $v1 (split(/,/,$pt->{$k})) {
1175                    $tmp2{$v1} = "";
1176                }
[236]1177            }
[1186]1178            if (keys %tmp2) {
1179                foreach $k (keys %tmp2) {
1180                    pb_log(0,"$k ");
1181                }
1182            } else {
1183                pb_log(0,"N/A");
[1185]1184            }
1185            pb_log(0,"\n");
[236]1186
[1185]1187            # Build files
1188            my @found;
1189            my @notfound;
1190            $pt = $h{'build'};
1191            foreach my $b (keys %$pt) {
1192                push @found,$b if ($pt->{$b} =~ /yes/);
1193                push @notfound,$b if ($pt->{$b} =~ /no/);
1194            }
1195            pb_log(0,"Build files have been generated for ... ".join(',',sort(@found))."\n") if (@found);
1196            pb_log(0,"No Build files found for ".join(',',sort(@notfound))."\n") if (@notfound);
1197
[556]1198        } else {
1199            # Instead call News generation
1200            pb_web_news2html($dest);
[559]1201            # And create an empty pbconf
1202            pb_mkdir_p("$dest/pbconf");
[560]1203            # And prepare the pbscript to execute remotely
[1138]1204            open(SCRIPT,"> $ENV{'PBTMP'}/pbscript") || die "Unable to create $ENV{'PBTMP'}/pbscript";
[560]1205            print SCRIPT "#!/bin/bash\n";
1206            print SCRIPT "#set -x\n";
1207            print SCRIPT "echo ... Extracting Website content\n";
[1461]1208            print SCRIPT "find . -type f | grep -Ev '^./$pbpkg-$pbver$pbextdir.tar.gz|^./pbscript' | xargs rm -f non-existent\n";
[560]1209            print SCRIPT "find * -type d -depth | xargs rmdir 2> /dev/null \n";
[1461]1210            print SCRIPT "tar xfz $pbpkg-$pbver$pbextdir.tar.gz\n";
1211            print SCRIPT "mv $pbpkg-$pbver$pbextdir/* .\n";
1212            print SCRIPT "rm -f $pbpkg-$pbver$pbextdir.tar.gz\n";
1213            print SCRIPT "rmdir $pbpkg-$pbver$pbextdir\n";
[1484]1214            print SCRIPT "find . -type f -print0 | xargs -0 chmod 644\n";
1215            print SCRIPT "find . -type d -print0 | xargs -0 chmod 755\n";
[560]1216            close(SCRIPT);
[1165]1217            chmod 0755,"$ENV{'PBTMP'}/pbscript";
[499]1218        }
1219
[1259]1220        # Apply filters to the non-build files
1221        my $liste ="";
1222        if (defined $filteredfiles->{$pbpkg}) {
1223            foreach my $f (split(/,/,$filteredfiles->{$pbpkg})) {
1224                pb_filter_file_inplace($ptr,"$dest/$f",$pb);
1225                $liste = "$f $liste";
1226            }
1227        }
1228        pb_log(2,"Files ".$liste."have been filtered\n");
1229
1230        # TODO: Make it CMS aware
1231        # Execute the pbinit script if any
1232        if (-x "$ENV{'PBROOTDIR'}/$pbpkg/pbinit") {
1233            pb_filter_file("$ENV{'PBROOTDIR'}/$pbpkg/pbinit",$ptr,"$ENV{'PBTMP'}/pbinit",$pb);
1234            chmod 0755,"$ENV{'PBTMP'}/pbinit";
1235            pb_system("cd $dest ; $ENV{'PBTMP'}/pbinit","Executing init script from $ENV{'PBROOTDIR'}/$pbpkg/pbinit under $dest","verbose");
1236        }
1237
1238        # Do we have additional script to run to prepare the environement for the project ?
1239        # Then include it in the pbconf delivery
1240        foreach my $pbvf (<$ENV{'PBROOTDIR'}/pbv*.pre>,<$ENV{'PBROOTDIR'}/pbv*.post>, <$ENV{'PBROOTDIR'}/pbtest*>) {
1241            if (-x "$pbvf") {
1242                my $target = "$ENV{'PBDESTDIR'}/".basename($pbvf);
1243                pb_filter_file("$pbvf",$ptr,$target,$pb);
1244                chmod 0755,"$target";
1245            }
1246        }
1247
[265]1248        # Prepare the dest directory for archive
[69]1249        chdir "$ENV{'PBDESTDIR'}" || die "Unable to change dir to $ENV{'PBDESTDIR'}";
[537]1250        if (defined $preserve) {
1251            # In that case we want to preserve the original tar file for checksum purposes
1252            # The one created is btw equivalent in that case to this one
1253            # Maybe check basename of both to be sure they are the same ?
1254            pb_log(0,"Preserving original tar file ");
[1432]1255            move("$preserve","$pbpkg-$pbver$pbextdir.tar.gz");
[537]1256        } else {
1257            # Possibility to look at PBSRC to guess more the filename
[1432]1258            pb_system("tar cfz $pbpkg-$pbver$pbextdir.tar.gz --exclude=$pbpkg-$pbver$pbextdir/pbconf $pbpkg-$pbver$pbextdir","Creating $pbpkg tar files compressed");
[537]1259        }
[1432]1260        pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz\n");
1261        pb_system("tar cfz $pbpkg-$pbver$pbextdir.pbconf.tar.gz $pbpkg-$pbver$pbextdir/pbconf","Creating pbconf tar files compressed");
1262        pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz\n");
[83]1263
[357]1264        # Keep track of version-tag per pkg
1265        $pkgs{$pbpkg} = "$pbver-$pbtag";
[83]1266
[288]1267        # Final cleanup
1268        pb_rm_rf($dest) if (-d $dest);
[9]1269    }
[357]1270
1271    # Keep track of per package version
1272    pb_log(2,"DEBUG pkgs: ".Dumper(%pkgs)."\n");
1273    open(PKG,"> $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb") || die "Unable to create $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb";
[539]1274    foreach my $pbpkg (keys %pkgs) {
[357]1275        print PKG "pbpkg $pbpkg = $pkgs{$pbpkg}\n";
1276    }
1277    close(PKG);
1278
1279    # Keep track of what is generated by default
1280    # We need to store the dir and info on version-tag
1281    # Base our content on the existing .pb file
1282    copy("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb","$ENV{'PBDESTDIR'}/pbrc");
1283    open(LAST,">> $ENV{'PBDESTDIR'}/pbrc") || die "Unable to create $ENV{'PBDESTDIR'}/pbrc";
1284    print LAST "pbroot $ENV{'PBPROJ'} = $ENV{'PBROOTDIR'}\n";
[702]1285    print LAST "projver $ENV{'PBPROJ'} = $ENV{'PBPROJVER'}\n";
1286    print LAST "projtag $ENV{'PBPROJ'} = $ENV{'PBPROJTAG'}\n";
[357]1287    print LAST "pbpackager $ENV{'PBPROJ'} = $ENV{'PBPACKAGER'}\n";
[1432]1288    print LAST "pbextdir $ENV{'PBPROJ'} = $pbextdir\n";
[357]1289    close(LAST);
[77]1290}
[22]1291
[772]1292sub pb_test2pkg {
1293    # Get the running distro to test on
[1177]1294    my $pbos = pb_distro_get_context();
[772]1295
1296    # Get list of packages to test
1297    # Get content saved in cms2build
1298    my $ptr = pb_get_pkg();
1299    @pkgs = @$ptr;
1300
1301    # Additional potential repo
[1177]1302    pb_distro_setuprepo($pbos);
[772]1303    foreach my $pbpkg (@pkgs) {
1304        # We need to install the package to test, and deps brought with it
[1177]1305        pb_distro_installdeps(undef,$pbos,$pbpkg);
[772]1306        pb_system("$ENV{'PBDESTDIR'}/pbtest","Launching test for $pbpkg","verbose");
1307    }
1308}
1309
[77]1310sub pb_build2pkg {
1311
[22]1312    # Get the running distro to build on
[1177]1313    my $pbos = pb_distro_get_context();
[22]1314
[1137]1315    # If needed we may add repository to the build env
[1177]1316    pb_distro_setuprepo($pbos);
[1137]1317
[353]1318    # Get list of packages to build
1319    my $ptr = pb_get_pkg();
1320    @pkgs = @$ptr;
1321
[898]1322    # Get content saved in cms2build
[353]1323    my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
[83]1324    $pkg = { } if (not defined $pkg);
[1432]1325    my $pbextdir = pb_get_extdir();
[83]1326
[1212]1327    pb_mkdir_p("$ENV{'PBBUILDDIR'}") if (! -d "$ENV{'PBBUILDDIR'}");
[1208]1328    chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
[126]1329    my $made = ""; # pkgs made during build
[1176]1330    my $pm;
1331    $pm = new Parallel::ForkManager($pbparallel) if (defined $pbparallel);
[1137]1332
1333    # We need to communicate info back from the children if parallel so prepare a dir for that
1334    my $tmpd = "$ENV{'PBTMP'}/build.$$";
1335    pb_mkdir_p($tmpd) if (defined $pbparallel);
1336
[27]1337    foreach my $pbpkg (@pkgs) {
[1137]1338        $pm->start and next if (defined $pbparallel);
1339
[88]1340        my $vertag = $pkg->{$pbpkg};
[1459]1341        pb_log(2,"Vertag: $vertag\n");
[77]1342        # get the version of the current package - maybe different
1343        ($pbver,$pbtag) = split(/-/,$vertag);
1344
[1432]1345        my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz";
1346        my $src2="$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz";
[315]1347        pb_log(2,"Source file: $src\n");
[493]1348        pb_log(2,"Pbconf file: $src2\n");
[25]1349
[315]1350        pb_log(2,"Working directory: $ENV{'PBBUILDDIR'}\n");
[1177]1351        if ($pbos->{'type'} eq "rpm") {
[25]1352            foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') {
[28]1353                if (! -d "$ENV{'PBBUILDDIR'}/$d") {
[1212]1354                    pb_mkdir_p("$ENV{'PBBUILDDIR'}/$d");
[28]1355                }
[25]1356            }
1357
[315]1358            # Remove in case a previous link/file was there
[301]1359            unlink "$ENV{'PBBUILDDIR'}/SOURCES/".basename($src);
[188]1360            symlink "$src","$ENV{'PBBUILDDIR'}/SOURCES/".basename($src) || die "Unable to symlink $src in $ENV{'PBBUILDDIR'}/SOURCES";
[25]1361            # We need to first extract the spec file
[1432]1362            my @specfile = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/","$ENV{'PBBUILDDIR'}/SPECS","spec");
[25]1363
[493]1364            # We need to handle potential patches to upstream sources
[1432]1365            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","$ENV{'PBBUILDDIR'}/SOURCES","patch");
[493]1366
[1219]1367            # We need to handle potential additional sources to upstream sources
[1432]1368            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}/SOURCES","src");
[1219]1369
[315]1370            pb_log(2,"specfile: ".Dumper(\@specfile)."\n");
[25]1371            # set LANGUAGE to check for correct log messages
1372            $ENV{'LANGUAGE'}="C";
[459]1373            # Older Redhat use _target_platform in %configure incorrectly
1374            my $specialdef = "";
[1177]1375            if (($pbos->{'name'} eq "redhat") || (($pbos->{'name'} eq "rhel") && ($pbos->{'version'} eq "2.1"))) {
[459]1376                $specialdef = "--define \'_target_platform \"\"\'";
1377            }
[702]1378
[28]1379            foreach my $f (@specfile) {
1380                if ($f =~ /\.spec$/) {
[1137]1381                    # This could cause an issue in // mode
[1177]1382                    pb_distro_installdeps($f,$pbos);
[1085]1383                    pb_system("rpmbuild $specialdef --define \"packager $ENV{'PBPACKAGER'}\" --define \"_topdir $ENV{'PBBUILDDIR'}\" -ba $f","Building package with $f under $ENV{'PBBUILDDIR'}","verbose");
[28]1384                    last;
1385                }
1386            }
[540]1387            # Get the name of the generated packages
[1137]1388            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
[540]1389            while (<LOG>) {
[572]1390                chomp($_);
[540]1391                next if ($_ !~ /^Wrote:/);
1392                s|.*/([S]*RPMS.*)|$1|;
[572]1393                $made .=" $_";
[540]1394            }
[541]1395            close(LOG);
[540]1396
[1177]1397        } elsif ($pbos->{'type'} eq "deb") {
[274]1398            pb_system("tar xfz $src","Extracting sources");
[493]1399            pb_system("tar xfz $src2","Extracting pbconf");
[149]1400
[1432]1401            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
[310]1402            pb_rm_rf("debian");
[1177]1403            symlink "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}","debian" || die "Unable to symlink to pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
[199]1404            chmod 0755,"debian/rules";
[544]1405
[1359]1406            # We need to handle potential patches to upstream sources
[1363]1407            pb_mkdir_p("debian/patches");
[1432]1408            my @f = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","debian/patches","patch");
[1363]1409
[1367]1410            # By default we use format 1.0 - Cf man dpkg-source
1411            my $debsrcfmt = "1.0";
1412            my $debsrcfile = "debian/source/format";
1413            if (-f $debsrcfile) {
1414                $debsrcfmt = pb_get_content($debsrcfile);
1415            }
1416               
1417            if ($debsrcfmt =~ /^3.*quilt/) {
1418                # If we use quilt to manage patches, we then setup the env correctly
1419                # as per http://pkg-perl.alioth.debian.org/howto/quilt.html
1420                # Generate Debian patch series for quilt
1421                open(SERIE,"> debian/patches/series") || die "Unable to write in debian/patches/series";
1422                $ENV{'QUILT_PATCHES'}="debian/patches";
1423            } else {
1424                # If we use dpatch to manage patches, we then setup the 00list file as well
1425                open(SERIE,"> debian/patches/00list") || die "Unable to write in debian/patches/00list";
1426            }
[1363]1427            foreach my $f (sort @f) {
[1367]1428                # Skip the script made to apply the patches to the Debian tree
1429                next if ($f =~ /pbapplypatch/);
1430                # We also need to uncompress them
1431                pb_system("gzip -d $f","","quiet");
1432                $f =~ s/\.gz$//;
[1359]1433                print SERIE "$f\n";
1434            }
1435            close(SERIE);
[1367]1436            if (@f) {
[1432]1437                # We have patches...
[1537]1438                my $patch_file = "debian/patches/pbapplypatch";
1439                if (($debsrcfmt =~ /^1.*/) && (-x $patch_file)) {
[1432]1440                    # In that case we need to apply the patches ourselves locally
[1537]1441                    pb_system("cat $patch_file","APPLY","verbose");
1442                    pb_system("$patch_file","Applying patches to $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} tree");
[1432]1443                }
1444                # ...so modify the name of files to be Debian compliant
1445                move("../$src","../$pbpkg-$pbver$pbextdir.orig.tar.gz");
[1367]1446            }
[1359]1447
1448            # We need to handle potential additional sources to upstream sources
[1432]1449            #pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}/debian","src");
[1359]1450
[1177]1451            pb_distro_installdeps("debian/control",$pbos);
[544]1452            pb_system("dpkg-buildpackage -us -uc -rfakeroot","Building package","verbose");
1453            # Get the name of the generated packages
[1137]1454            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
[544]1455            while (<LOG>) {
1456                chomp();
1457                my $tmp = $_;
[567]1458                next if ($tmp !~ /^dpkg-deb.*:/);
[1234]1459                $tmp =~ s|.*\.\./(.*)_(.*).deb.*|$1|;
[544]1460                $made="$made $tmp.dsc $tmp.tar.gz $tmp"."_*.deb $tmp"."_*.changes";
[448]1461            }
[544]1462            close(LOG);
[1234]1463            chdir ".." || die "Unable to chdir to parent dir";
[1424]1464            pb_rm_rf("$pbpkg-$pbver");
[1177]1465        } elsif ($pbos->{'type'} eq "ebuild") {
[149]1466            my @ebuildfile;
1467            # For gentoo we need to take pb as subsystem name
[295]1468            # We put every apps here under sys-apps. hope it's correct
[435]1469            # We use pb's home dir in order to have a single OVERLAY line
[1185]1470            my $tmpe = "$ENV{'HOME'}/portage/pb/sys-apps/$pbpkg";
1471            pb_mkdir_p($tmpe) if (! -d "$tmpe");
[295]1472            pb_mkdir_p("$ENV{'HOME'}/portage/distfiles") if (! -d "$ENV{'HOME'}/portage/distfiles");
[149]1473
[295]1474            # We need to first extract the ebuild file
[1432]1475            @ebuildfile = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/","$tmpe","ebuild");
[149]1476
1477            # Prepare the build env for gentoo
1478            my $found = 0;
[295]1479            my $pbbd = $ENV{'HOME'};
[150]1480            $pbbd =~ s|/|\\/|g;
[295]1481            if (-r "/etc/make.conf") {
1482                open(MAKE,"/etc/make.conf");
1483                while (<MAKE>) {
1484                    $found = 1 if (/$pbbd\/portage/);
1485                }
1486                close(MAKE);
[149]1487            }
1488            if ($found == 0) {
[295]1489                pb_system("sudo sh -c 'echo PORTDIR_OVERLAY=\"$ENV{'HOME'}/portage\" >> /etc/make.conf'");
[149]1490            }
[295]1491            #$found = 0;
1492            #if (-r "/etc/portage/package.keywords") {
1493            #open(KEYW,"/etc/portage/package.keywords");
1494            #while (<KEYW>) {
1495            #$found = 1 if (/portage\/pb/);
1496            #}
1497            #close(KEYW);
1498            #}
1499            #if ($found == 0) {
1500            #pb_system("sudo sh -c \"echo portage/pb >> /etc/portage/package.keywords\"");
1501            #}
[149]1502
1503            # Build
1504            foreach my $f (@ebuildfile) {
1505                if ($f =~ /\.ebuild$/) {
[1177]1506                    pb_distro_installdeps($f,$pbos);
[1185]1507                    move($f,"$tmpe/$pbpkg-$pbver.ebuild");
1508                    pb_system("cd $tmpe ; ebuild $pbpkg-$pbver.ebuild clean ; ebuild $pbpkg-$pbver.ebuild digest ; ebuild $pbpkg-$pbver.ebuild package","verbose");
[295]1509                    # Now move it where pb expects it
1510                    pb_mkdir_p("$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
[1432]1511                    if ($pbtag eq 0) {
1512                        # This is assumed to be a test version
1513                        my $nver = substr($pbver,0,-14);
1514                        my $ntag = substr($pbver,-14);
1515                        my $ebtg = "portage/pb/sys-apps/$pbpkg/$pbpkg-$nver"."_p$ntag.ebuild";
1516                        move("$tmpe/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/$ebtg");
1517                        $made="$made $ebtg";
[1174]1518                    } else {
[1432]1519                        my $ebtg = "portage/pb/sys-apps/$pbpkg/$pbpkg-$pbver-r$pbtag.ebuild";
1520                        move("$tmpe/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/$ebtg");
1521                        $made="$made $ebtg";
[1174]1522                    }
[149]1523                }
1524            }
1525
[1177]1526        } elsif ($pbos->{'type'} eq "tgz") {
[437]1527            # Slackware family
[435]1528            $made="$made $pbpkg/$pbpkg-$pbver-*-$pbtag.tgz";
1529
1530            pb_system("tar xfz $src","Extracting sources");
[493]1531            pb_system("tar xfz $src2","Extracting pbconf");
[1432]1532            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
[1177]1533            symlink "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}","install" || die "Unable to symlink to pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
[435]1534            if (-x "install/pbslack") {
[1177]1535                pb_distro_installdeps("./install/pbslack",$pbos);
[872]1536                pb_system("./install/pbslack","Building software");
[529]1537                pb_system("sudo /sbin/makepkg -p -l y -c y $pbpkg","Packaging $pbpkg","verbose");
[435]1538            }
[1234]1539            chdir ".." || die "Unable to chdir to parent dir";
[1432]1540            pb_rm_rf("$pbpkg-$pbver$pbextdir");
[1177]1541        } elsif ($pbos->{'type'} eq "pkg") {
[872]1542            # Solaris
[916]1543            $made="$made $pbpkg-$pbver-$pbtag.pkg.gz";
[873]1544            my $pkgdestdir="$ENV{'PBBUILDDIR'}/install";
[872]1545
1546            # Will host resulting packages
[1177]1547            pb_mkdir_p("$pbos->{'type'}");
[878]1548            pb_mkdir_p("$pkgdestdir/delivery");
[873]1549            pb_system("tar xfz $src","Extracting sources under $ENV{'PBBUILDDIR'}");
1550            pb_system("tar xfz $src2","Extracting pbconf under $ENV{'PBBUILDDIR'}");
[1242]1551            # We need to handle potential patches to upstream sources
[1432]1552            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","$ENV{'PBBUILDDIR'}","patch");
[1242]1553
1554            # We need to handle potential additional sources to upstream sources
[1432]1555            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}","src");
[1242]1556
[1432]1557            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
[1177]1558            if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild") {
1559                chmod 0755,"pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild";
[872]1560                # pkginfo file is mandatory
[1177]1561                die "Unable to find pkginfo file in pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}" if (! -f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pkginfo");
[872]1562                # Build
[1177]1563                pb_system("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild $pkgdestdir/delivery","Building software and installing under $pkgdestdir/delivery");
[872]1564                # Copy complementary files
[1177]1565                if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/prototype") {
1566                    copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/prototype", $pkgdestdir) 
[872]1567                } else {
1568                    # No prototype provided, calculating it
[878]1569                    open(PROTO,"> $pkgdestdir/prototype") || die "Unable to create prototype file";
[872]1570                    print PROTO "i pkginfo\n";
[1177]1571                    print PROTO "i depend\n" if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend");
[879]1572                    $ENV{'PBSOLDESTDIR'} = "$pkgdestdir/delivery";
1573                    find(\&create_solaris_prototype, "$pkgdestdir/delivery");
[872]1574                }
[1177]1575                copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend", $pkgdestdir) if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend");
1576                copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pkginfo", $pkgdestdir);
1577                pb_system("cd $pkgdestdir/delivery ; pkgmk -o -f ../prototype -r $pkgdestdir/delivery -d $ENV{'PBBUILDDIR'}/$pbos->{'type'}","Packaging $pbpkg","verbose");
1578                pb_system("cd $ENV{'PBBUILDDIR'}/$pbos->{'type'} ;  echo \"\" | pkgtrans -o -n -s $ENV{'PBBUILDDIR'}/$pbos->{'type'} $ENV{'PBBUILDDIR'}/$pbpkg-$pbver-$pbtag.pkg all","Transforming $pbpkg","verbose");
[916]1579                pb_system("cd $ENV{'PBBUILDDIR'} ;  gzip -9f $pbpkg-$pbver-$pbtag.pkg","Compressing $pbpkg-$pbver-$pbtag.pkg","verbose");
[913]1580            } else {
[1177]1581                pb_log(0,"No pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild file found for $pbpkg-$pbver in \n");
[872]1582            }
[874]1583            chdir ".." || die "Unable to chdir to parent dir";
[1432]1584            pb_rm_rf("$pbpkg-$pbver$pbextdir","$ENV{'PBBUILDDIR'}/$pbos->{'type'}","$pkgdestdir");
[1177]1585        } elsif ($pbos->{'type'} eq "hpux") {
[1174]1586            # HP-UX
1587            pb_system("tar xfz $src","Extracting sources");
1588            pb_system("tar xfz $src2","Extracting pbconf");
1589
[1432]1590            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
[1174]1591            pb_system("buildpackage ","Building package","verbose");
1592            # Get the name of the generated packages
1593            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
1594            while (<LOG>) {
1595                chomp();
1596                my $tmp = $_;
1597                next if ($tmp !~ /^SD BUILD.*:/);
1598                $tmp =~ s|.*../(.*)_(.*).sd.*|$1|;
[1279]1599                $made = "$made $tmp"."_*.sd";
[1174]1600            }
1601            close(LOG);
1602            $made="$made $pbpkg-$pbver-$pbtag.sd";
1603
[1234]1604            chdir ".." || die "Unable to chdir to parent dir";
[1432]1605            pb_rm_rf("$pbpkg-$pbver$pbextdir");
[87]1606        } else {
[1177]1607            die "Unknown OS type format $pbos->{'type'}";
[87]1608        }
[1137]1609        if (defined $pbparallel) {
1610            # Communicate results back to parent
1611            pb_set_content("$tmpd/$$",$made);
1612            $pm->finish;
1613        }
[87]1614    }
[1137]1615    if (defined $pbparallel) {
1616        # In the parent, we need to get the result from the children
1617        $pm->wait_all_children;
1618        foreach my $f (<$tmpd/*>) {
1619            $made .= " ".pb_get_content($f);
1620        }
1621        pb_rm_rf($tmpd);
1622    }
1623
[1278]1624    # Sign packages
1625    pb_sign_pkgs($pbos,$made);
1626
[1109]1627    # Find the appropriate check cmd/opts
[1177]1628    my ($chkcmd,$chkopt) = pb_distro_get_param($pbos,pb_conf_get_if("oschkcmd","oschkopt"));
[1109]1629
[541]1630    # Packages check if needed
[1177]1631    if ($pbos->{'type'} eq "rpm") {
1632        if ((defined  $chkcmd) && (-x $chkcmd)) {
1633            my $cmd = "$chkcmd";
1634            $cmd .= " $chkopt" if (defined $chkopt);
1635            $cmd .= " $made";
[1539]1636            my $ret = pb_system("$cmd","Checking validity of rpms with $chkcmd","verbose",1);
1637            pb_log(0,"ERROR: when checking packages validity\n") if ($ret ne 0);
[541]1638        }
[1098]1639        my $rpms ="";
1640        my $srpms ="";
1641        foreach my $f (split(/ /,$made)) {
1642            $rpms .= "$ENV{'PBBUILDDIR'}/$f " if ($f =~ /^RPMS\//);
1643            $srpms .= "$ENV{'PBBUILDDIR'}/$f " if ($f =~ /^SRPMS\//);
1644        }
1645        pb_log(0,"SRPM packages generated: $srpms\n");
1646        pb_log(0,"RPM packages generated: $rpms\n");
[1177]1647    } elsif ($pbos->{'type'} eq "deb") {
[572]1648        my $made2 = "";
[971]1649        foreach my $f (split(/ /,$made)) {
[1234]1650            $made2 .= "$f " if ($f =~ /\.deb$/);
[971]1651        }
[1109]1652        if (-x $chkcmd) {
[1539]1653            my $ret = pb_system("$chkcmd $chkopt $made2","Checking validity of debs with $chkcmd","verbose",1);
1654            pb_log(0,"ERROR: when checking packages validity\n") if ($ret ne 0);
[541]1655        }
[1234]1656        pb_log(0,"deb packages generated: $made2\n");
[541]1657    } else {
[1177]1658        pb_log(0,"No check done for $pbos->{'type'} yet\n");
[572]1659        pb_log(0,"Packages generated: $made\n");
[541]1660    }
1661
[1176]1662    # Keep track of what is generated so that we can get them back from VMs/RMs
[1189]1663    open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") || die "Unable to create $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
[118]1664    print KEEP "$made\n";
1665    close(KEEP);
[87]1666}
1667
[874]1668sub create_solaris_prototype {
[872]1669
[873]1670    my $uidgid = "bin bin";
[877]1671    my $pkgdestdir = $ENV{'PBSOLDESTDIR'};
[872]1672
[878]1673    return if ($_ =~ /^$pkgdestdir$/);
[875]1674    if (-d $_) {
1675        my $n = $File::Find::name;
1676        $n =~ s~$pkgdestdir/~~;
1677        print PROTO "d none $n 0755 $uidgid\n";
[877]1678    } elsif (-x $_) {
[875]1679        my $n = $File::Find::name;
1680        $n =~ s~$pkgdestdir/~~;
1681        print PROTO "f none $n 0755 $uidgid\n";
[872]1682    } elsif (-f $_) {
[875]1683        my $n = $File::Find::name;
1684        $n =~ s~$pkgdestdir/~~;
1685        print PROTO "f none $n 0644 $uidgid\n";
[872]1686    }
1687}
1688
[88]1689sub pb_build2ssh {
[320]1690    pb_send2target("Sources");
[1374]1691    pb_send2target("CPAN");
[90]1692}
[87]1693
[90]1694sub pb_pkg2ssh {
[320]1695    pb_send2target("Packages");
[90]1696}
1697
[108]1698# By default deliver to the the public site hosting the
[1176]1699# ftp structure (or whatever) or a VM/VE/RM
[320]1700sub pb_send2target {
[90]1701
1702    my $cmt = shift;
[320]1703    my $v = shift || undef;
[142]1704    my $vmexist = shift || 0;           # 0 is FALSE
[200]1705    my $vmpid = shift || 0;             # 0 is FALSE
[748]1706    my $snapme = shift || 0;            # 0 is FALSE
[320]1707
[444]1708    pb_log(2,"DEBUG: pb_send2target($cmt,".Dumper($v).",$vmexist,$vmpid)\n");
[320]1709    my $host = "sshhost";
1710    my $login = "sshlogin";
1711    my $dir = "sshdir";
1712    my $port = "sshport";
1713    my $conf = "sshconf";
[883]1714    my $tmout = undef;
1715    my $path = undef;
[772]1716    if ($cmt =~ /^VM/) {
[320]1717        $login = "vmlogin";
[322]1718        $dir = "pbdefdir";
[320]1719        # Specific VM
[883]1720        $tmout = "vmtmout";
1721        $path = "vmpath";
[320]1722        $host = "vmhost";
1723        $port = "vmport";
[1176]1724    } elsif ($cmt =~ /^RM/) {
1725        $login = "rmlogin";
1726        $dir = "pbdefdir";
1727        # Specific RM
1728        $tmout = "rmtmout";
1729        $path = "rmpath";
1730        $host = "rmhost";
1731        $port = "rmport";
[772]1732    } elsif ($cmt =~ /^VE/) {
[320]1733        $login = "velogin";
[322]1734        $dir = "pbdefdir";
[320]1735        # Specific VE
1736        $path = "vepath";
[986]1737        $conf = "rbsconf";
[556]1738    } elsif ($cmt eq "Web") {
1739        $host = "websshhost";
1740        $login = "websshlogin";
1741        $dir = "websshdir";
1742        $port = "websshport";
[1374]1743    } elsif ($cmt eq "CPAN") {
1744        $host = "cpanpause";
1745        $login = "";
1746        $dir = "cpandir";
1747        $port = "";
[320]1748    }
[158]1749    my $cmd = "";
[471]1750    my $src = "";
[1374]1751    my $cpanpkg = 0;
[1177]1752    my $pbos;
[90]1753
[1432]1754    my $pbextdir = pb_get_extdir();
1755
[471]1756    if ($cmt ne "Announce") {
[898]1757        # Get list of packages to build
[471]1758        my $ptr = pb_get_pkg();
1759        @pkgs = @$ptr;
[87]1760
[471]1761        # Get the running distro to consider
[1177]1762        $pbos = pb_distro_get_context($v);
[87]1763
[471]1764        # Get content saved in cms2build
1765        my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
1766        $pkg = { } if (not defined $pkg);
[87]1767
[1212]1768        pb_mkdir_p("$ENV{'PBBUILDDIR'}") if (! -d "$ENV{'PBBUILDDIR'}");
[1208]1769        chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
[471]1770        foreach my $pbpkg (@pkgs) {
1771            my $vertag = $pkg->{$pbpkg};
1772            # get the version of the current package - maybe different
[1459]1773            pb_log(2,"Vertag: $vertag\n");
[471]1774            ($pbver,$pbtag) = split(/-/,$vertag);
[87]1775
[1179]1776            if (($cmt eq "Sources") || ($cmt =~ /(V[EM]|RM)build/)) {
[1432]1777                $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz";
[471]1778                if ($cmd eq "") {
[1432]1779                    $cmd = "ln -sf $pbpkg-$pbver$pbextdir.tar.gz $pbpkg-latest.tar.gz";
[471]1780                } else {
[1432]1781                    $cmd = "$cmd ; ln -sf $pbpkg-$pbver$pbextdir.tar.gz $pbpkg-latest.tar.gz";
[471]1782                }
[560]1783            } elsif ($cmt eq "Web") {
[1432]1784                $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz"
[166]1785            }
[1374]1786
1787            # Do we have one perl package
1788            my @nametype = pb_conf_get_if("namingtype");
1789            my $type = $nametype[0]->{$pbpkg};
1790            if ((defined $type) && ($type eq "perl")) {
1791                $cpanpkg = 1;
1792            }
[118]1793        }
[471]1794        # Adds conf file for availability of conf elements
1795        pb_conf_add("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb");
[118]1796    }
[1374]1797    my ($rbsconf,$testver,$delivery) = pb_conf_get_if($conf,"testver","delivery");
1798    if ($cmt =~ /CPAN/) {
1799        # Do not deliver on Pause if this is a test version
[1384]1800        return if (not defined $testver);
[1374]1801        return if ($testver =~ /true/);
1802        # Do not deliver on Pause if this is not a perl package
1803        return if ($cpanpkg == 0);
1804    }
[417]1805
[1176]1806    if ($cmt =~ /(V[EM]|RM)build/) {
[1138]1807        $src="$src $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb $ENV{'PBETC'} $ENV{'PBDESTDIR'}/pbrc $ENV{'PBDESTDIR'}/pbscript.$$";
[1176]1808    } elsif ($cmt =~ /(V[EM]|RM)Script/) {
[1138]1809        $src="$src $ENV{'PBDESTDIR'}/pbscript.$$";
[1176]1810    } elsif ($cmt =~ /(V[EM]|RM)test/) {
[1138]1811        $src="$src $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb $ENV{'PBETC'} $ENV{'PBDESTDIR'}/pbrc $ENV{'PBDESTDIR'}/pbscript.$$ $ENV{'PBDESTDIR'}/pbtest";
[1374]1812    } elsif (($cmt eq "Announce") || ($cmt eq "Web") || ($cmt eq "CPAN")) {
[471]1813        $src="$src $ENV{'PBTMP'}/pbscript";
[118]1814    } elsif ($cmt eq "Packages") {
1815        # Get package list from file made during build2pkg
[1189]1816        open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
[126]1817        $src = <KEEP>;
[118]1818        chomp($src);
1819        close(KEEP);
[1279]1820        $src = "$src $ENV{'PBBUILDDIR'}/pbscript.$$";
[87]1821    }
[1374]1822    if (($cmt eq "Sources") || ($cmt eq "Packages") || ($cmt eq "CPAN")) {
[1279]1823        my ($pbpackager) = pb_conf_get("pbpackager");
1824        $ENV{'PBPACKAGER'} = $pbpackager->{$ENV{'PBPROJ'}};
1825        pb_log(0,"Exporting public key for $ENV{'PBPACKAGER'}\n");
1826        # Using pb_system is not working due to redirection below
1827        system("gpg --export -a \'$ENV{'PBPACKAGER'}\' > $ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey");
1828        chmod 0644,"$ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey";
1829        $src = "$src $ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey";
1830    }
[320]1831    # Remove potential leading spaces (cause problem with basename)
[132]1832    $src =~ s/^ *//;
[129]1833    my $basesrc = "";
[131]1834    foreach my $i (split(/ +/,$src)) {
1835        $basesrc .= " ".basename($i);
[130]1836    }
[118]1837
[320]1838    pb_log(0,"Sources handled ($cmt): $src\n");
[987]1839    pb_log(2,"values: ".Dumper(($host,$login,$dir,$port,$tmout,$path,$conf))."\n");
[1541]1840    my ($sshhost,$sshdir) = pb_conf_get($host,$dir);
[883]1841    # Not mandatory...
[1102]1842    $delivery->{$ENV{'PBPROJ'}} = "" if (not defined $delivery->{$ENV{'PBPROJ'}});
[1541]1843    my ($sshlogin,$sshport) = pb_conf_get_if($login,$port);
1844    $sshport->{$ENV{PBPROJ}} = 22 unless (defined $sshport->{$ENV{PBPROJ}});
1845    $sshlogin->{$ENV{PBPROJ}} = getpwuid($UID) unless (defined $sshlogin->{$ENV{PBPROJ}});
[883]1846    my ($vtmout,$vepath);
1847    # ...Except those in virtual context
1848    if ($cmt =~ /^VE/) {
1849        ($vepath) = pb_conf_get($path);
1850    }
[1176]1851    if ($cmt =~ /^(V|R)M/) {
[1218]1852        $vtmout = pb_distro_get_param($pbos,pb_conf_get_if($tmout));
[883]1853    }
[1216]1854    my $remhost = $sshhost->{$ENV{'PBPROJ'}};
1855    my $remdir = $sshdir->{$ENV{'PBPROJ'}};
1856    if ($cmt =~ /^V[EM]|RM/) {
1857        # In that case our real host is in the xxhost with the OS as key, not project as above
1858        $remhost = pb_distro_get_param($pbos,$sshhost);
[1176]1859    }
[1217]1860    pb_log(2,"ssh: ".Dumper(($remhost,$sshlogin,$remdir,$sshport,$vepath,$rbsconf))."\n");
1861    pb_log(2,"ssh: ".Dumper($vtmout)."\n") if (defined $vtmout);
[320]1862
1863    my $mac;
[772]1864    if ($cmt !~ /^VE/) {
[1216]1865        $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$remhost";
[320]1866        # Overwrite account value if passed as parameter
[1216]1867        $mac = "$pbaccount\@$remhost" if (defined $pbaccount);
[355]1868        pb_log(2, "DEBUG: pbaccount: $pbaccount => mac: $mac\n") if (defined $pbaccount);
[681]1869    } else {
1870        # VE
[1138]1871        # Overwrite account value if passed as parameter (typically for setup2v)
[681]1872        $mac = $sshlogin->{$ENV{'PBPROJ'}};
1873        $mac = $pbaccount if (defined $pbaccount);
[320]1874    }
1875
[108]1876    my $tdir;
[136]1877    my $bdir;
[1176]1878    if (($cmt eq "Sources") || ($cmt =~ /(V[EM]|RM)Script/)) {
[1216]1879        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/src";
[1374]1880    } elsif ($cmt eq "CPAN") {
1881        $tdir = "$remdir";
[1176]1882    } elsif ($cmt =~ /(V[EM]|RM)(build|test)/) {
[1216]1883        $tdir = $remdir."/$ENV{'PBPROJ'}/delivery";
1884        $bdir = $remdir."/$ENV{'PBPROJ'}/build";
[136]1885        # Remove a potential $ENV{'HOME'} as bdir should be relative to pb's home
1886        $bdir =~ s|\$ENV.+\}/||;
[471]1887    } elsif ($cmt eq "Announce") {
[1216]1888        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}";
[556]1889    } elsif ($cmt eq "Web") {
[1216]1890        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}";
[90]1891    } elsif ($cmt eq "Packages") {
[1192]1892        if (($pbos->{'type'} eq "rpm") || ($pbos->{'type'} eq "pkg") || ($pbos->{'type'} eq "hpux") || ($pbos->{'type'} eq "tgz")) {
1893            # put packages under an arch subdir
[1216]1894            $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}";
[1192]1895        } elsif (($pbos->{'type'} eq "deb") || ($pbos->{'type'} eq "ebuild")) {
1896            # No need for an arch subdir
[1216]1897            $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}";
[1192]1898        } else {
1899            die "Please teach the dev team where to deliver ($pbos->{'type'} type of packages\n";
1900        }
[429]1901
1902        my $repodir = $tdir;
[1216]1903        $repodir =~ s|^$remdir/||;
[429]1904
1905        my ($pbrepo) = pb_conf_get("pbrepo");
1906
1907        # Repository management
[1189]1908        open(PBS,"> $ENV{'PBBUILDDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBBUILDDIR'}/pbscript.$$";
[1177]1909        if ($pbos->{'type'} eq "rpm") {
[1276]1910            my $pbsha = pb_distro_get_param($pbos,pb_conf_get("ossha"));
[429]1911            # Also make a pbscript to generate yum/urpmi bases
1912            print PBS << "EOF";
[433]1913#!/bin/bash
[429]1914# Prepare a script to ease yum setup
[1298]1915EOF
1916            print PBS "set -x\n" if ($pbdebug gt 1);
1917            print PBS << "EOF";
[429]1918cat > $ENV{'PBPROJ'}.repo << EOT
1919[$ENV{'PBPROJ'}]
[1177]1920name=$pbos->{'name'} $pbos->{'version'} $pbos->{'arch'} - $ENV{'PBPROJ'} Vanilla Packages
[433]1921baseurl=$pbrepo->{$ENV{'PBPROJ'}}/$repodir
[429]1922enabled=1
[1289]1923gpgcheck=1
[1335]1924gpgkey=$pbrepo->{$ENV{'PBPROJ'}}/$repodir/$ENV{'PBPROJ'}.pubkey
[429]1925EOT
1926chmod 644 $ENV{'PBPROJ'}.repo
1927
1928# Clean up old repo content
1929rm -rf headers/ repodata/
1930# Create yum repo
[1102]1931if [ -x /usr/bin/yum-arch ]; then
1932    yum-arch .
1933fi
[429]1934# Create repodata
[1276]1935createrepo -s $pbsha .
[1365]1936# Link to the key
[1409]1937(cd repodata ; ln -sf ../$ENV{'PBPROJ'}.pubkey repomd.xml.key)
[1365]1938# sign the repomd (at least useful for SLES - which requires a local key)
1939# gpg -a --detach-sign repodata/repomd.xml
1940# SLES also looks for media.1/info.txt
[429]1941EOF
[1177]1942            if ($pbos->{'family'} eq "md") {
[429]1943                # For Mandriva add urpmi management
1944                print PBS << "EOF";
1945# Prepare a script to ease urpmi setup
1946cat > $ENV{'PBPROJ'}.addmedia << EOT
[1003]1947urpmi.addmedia $ENV{'PBPROJ'} $pbrepo->{$ENV{'PBPROJ'}}/$repodir with media_info/hdlist.cz
[429]1948EOT
1949chmod 755 $ENV{'PBPROJ'}.addmedia
1950
1951# Clean up old repo content
[437]1952rm -f hdlist.cz synthesis.hdlist.cz
[429]1953# Create urpmi repo
[1002]1954genhdlist2 --clean .
1955if [ \$\? -ne 0 ]; then
1956    genhdlist .
1957fi
[429]1958EOF
1959            }
[1177]1960            if ($pbos->{'name'} eq "fedora") {
[484]1961                # Extract the spec file to please Fedora maintainers :-(
1962                print PBS << "EOF";
1963for p in $basesrc; do
1964    echo \$p | grep -q 'src.rpm'
1965    if [ \$\? -eq 0 ]; then
1966        rpm2cpio \$p | cpio -ivdum --quiet '*.spec'
1967    fi
1968done
1969EOF
1970            }
[1177]1971            if ($pbos->{'family'} eq "novell") {
[1089]1972                # Add ymp scripts for one-click install on SuSE
1973                print PBS << "EOF";
1974# Prepare a script to ease SuSE one-click install
[1090]1975# Cf: http://de.opensuse.org/1-Klick-Installation/ISV
1976#
[1089]1977cat > $ENV{'PBPROJ'}.ymp << EOT
[1096]1978<?xml version="1.0" encoding="utf-8"?>
1979<!-- vim: set sw=2 ts=2 ai et: -->
[1089]1980<metapackage xmlns:os="http://opensuse.org/Standards/One_Click_Install" xmlns="http://opensuse.org/Standards/One_Click_Install">
1981    <group><!-- The group of software, typically one for project-builder.org -->
1982        <name>$ENV{'PBPROJ'} Bundle</name> <!-- Name of the software group -->
1983        <summary>Software bundle for the $ENV{'PBPROJ'} project</summary> <!--This message is shown to the user and should describe the whole bundle -->
[1095]1984        <description>This is the summary of the $ENV{'PBPROJ'} Project
[1089]1985             
[1095]1986            Details are available on a per package basis below
1987
[1089]1988        </description><!--This is also shown to the user -->
1989        <remainSubscribed>false</remainSubscribed> <!-- Don't know what it mean -->
1990        <repositories><!-- List of needed repositories -->
1991            <repository>
1992                <name>$ENV{'PBPROJ'} Repository</name> <!-- Name of the repository  -->
1993                <summary>This repository contains the $ENV{'PBPROJ'} project packages.</summary> <!-- Summary of the repository -->
1994                <description>This repository contains the $ENV{'PBPROJ'} project packages.</description><!-- This description is shown to the user -->
1995                <url>$pbrepo->{$ENV{'PBPROJ'}}/$repodir</url><!--URL of repository, which is added -->
1996            </repository>
1997        </repositories>
1998        <software><!-- A List of packages, which should be added through the one-click-installation -->
1999EOT
2000for p in $basesrc; do
2001    sum=`rpm -q --qf '%{SUMMARY}' \$p`
[1096]2002    name=`rpm -q --qf '%{NAME}' \$p`
[1089]2003    desc=`rpm -q --qf '%{description}' \$p`
2004    cat >> $ENV{'PBPROJ'}.ymp << EOT
2005            <item>
[1096]2006                <name>\$name</name><!-- Name of the package, is shown to the user and used to identify the package at the repository -->
[1089]2007                <summary>\$sum</summary> <!-- Summary of the package -->
2008                <description>\$desc</description> <!-- Description, is shown to the user -->
2009            </item>
2010EOT
2011done
2012cat >> $ENV{'PBPROJ'}.ymp << EOT
2013        </software>
2014    </group>
2015</metapackage>
2016EOT
2017chmod 644 $ENV{'PBPROJ'}.ymp
2018EOF
2019            }
[1177]2020        } elsif ($pbos->{'type'} eq "deb") {
[429]2021            # Also make a pbscript to generate apt bases
[460]2022            # Cf: http://www.debian.org/doc/manuals/repository-howto/repository-howto.fr.html
[1246]2023            # This dirname removes ver
[1283]2024            my $debarch = $pbos->{'arch'};
[1287]2025            $debarch = "amd64" if ($pbos->{'arch'} eq "x86_64");
[465]2026            my $rpd = dirname("$pbrepo->{$ENV{'PBPROJ'}}/$repodir");
[1357]2027            # Remove extra . in path to fix #522
2028            $rpd =~ s|/./|/|g;
[460]2029            print PBS << "EOF";
[465]2030#!/bin/bash
2031# Prepare a script to ease apt setup
2032cat > $ENV{'PBPROJ'}.sources.list << EOT
[1177]2033deb $rpd $pbos->{'version'} contrib
2034deb-src $rpd $pbos->{'version'} contrib
[460]2035EOT
[465]2036chmod 644 $ENV{'PBPROJ'}.sources.list
[460]2037
[1112]2038# Up two levels to deal with the dist dir cross versions
[1192]2039cd ..
[1275]2040mkdir -p dists/$pbos->{'version'}/contrib/binary-$debarch dists/$pbos->{'version'}/contrib/source
[1112]2041
[460]2042# Prepare a script to create apt info file
[1192]2043# Reuse twice after
[1112]2044TMPD=`mktemp -d /tmp/pb.XXXXXXXXXX` || exit 1
2045mkdir -p \$TMPD
2046cat > \$TMPD/Release << EOT
2047Archive: unstable
2048Component: contrib
2049Origin: $ENV{'PBPROJ'}
2050Label: $ENV{'PBPROJ'} dev repository $pbrepo->{$ENV{'PBPROJ'}}
2051EOT
2052
[1275]2053echo "Creating Packages metadata ($pbos->{'arch'} aka $debarch)"
2054dpkg-scanpackages -a$debarch $pbos->{'version'} /dev/null | gzip -c9 > dists/$pbos->{'version'}/contrib/binary-$debarch/Packages.gz
2055dpkg-scanpackages -a$debarch $pbos->{'version'} /dev/null | bzip2 -c9 > dists/$pbos->{'version'}/contrib/binary-$debarch/Packages.bz2
[1192]2056echo "Creating Contents metadata"
2057apt-ftparchive contents $pbos->{'version'} | gzip -c9 > dists/$pbos->{'version'}/Contents.gz
[1275]2058echo "Creating Release metadata ($pbos->{'arch'} aka $debarch)"
2059cat \$TMPD/Release > dists/$pbos->{'version'}/contrib/binary-$debarch/Release
[1279]2060echo "Architecture: $debarch" >> dists/$pbos->{'version'}/contrib/binary-$debarch/Release
[1112]2061echo "Creating Source metadata"
[1192]2062dpkg-scansources $pbos->{'version'} /dev/null | gzip -c9 > dists/$pbos->{'version'}/contrib/source/Sources.gz
[1177]2063cat \$TMPD/Release > dists/$pbos->{'version'}/contrib/source/Release
2064echo "Architecture: Source" >> dists/$pbos->{'version'}/contrib/source/Release
[1112]2065echo "Creating Release metadata"
[1388]2066# Signing that file would be useful but uneasy as gpg keys are not there
2067# Cf: http://wiki.debian.org/SecureApt
2068# Same as for repomd
[1177]2069apt-ftparchive release dists/$pbos->{'version'} > dists/$pbos->{'version'}/Release
[1112]2070rm -rf \$TMPD
[460]2071EOF
[1177]2072        } elsif ($pbos->{'type'} eq "ebuild") {
[586]2073            # make a pbscript to generate links to latest version
2074            print PBS << "EOF";
2075#!/bin/bash
2076# Prepare a script to create correct links
2077for p in $src; do
2078    echo \$p | grep -q '.ebuild'
2079    if [ \$\? -eq 0 ]; then
2080        j=`basename \$p`
2081        pp=`echo \$j | cut -d'-' -f1`
2082        ln -sf \$j \$pp.ebuild
2083    fi
2084done
2085EOF
[429]2086        }
2087        close(PBS);
[1189]2088        chmod 0755,"$ENV{'PBBUILDDIR'}/pbscript.$$";
[90]2089    } else {
2090        return;
[22]2091    }
[239]2092
[1143]2093    # Useless for VE
[1179]2094    my $nport = pb_get_port($sshport,$pbos,$cmt) if ($cmt !~ /^VE/);
[320]2095
[136]2096    # Remove a potential $ENV{'HOME'} as tdir should be relative to pb's home
[132]2097    $tdir =~ s|\$ENV.+\}/||;
2098
[1217]2099    my $tm = "";
[1176]2100    if ($cmt =~ /^(V|R)M/) {
[1218]2101        $tm = "sleep $vtmout" if (defined $vtmout);
[883]2102    }
[320]2103
[1374]2104    # ssh communication if not VE or CPAN
[349]2105    # should use a hash instead...
[320]2106    my ($shcmd,$cpcmd,$cptarget,$cp2target);
[1374]2107    if ($cmt =~ /^VE/) {
[1541]2108        my $tp = pb_path_expand($vepath->{$ENV{'PBPROJ'}});
2109        my $tpdir = pb_path_expand("$tp/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
[681]2110        my ($ptr) = pb_conf_get("vetype");
2111        my $vetype = $ptr->{$ENV{'PBPROJ'}};
2112        if ($vetype eq "chroot") {
[1179]2113            $shcmd = "sudo /usr/sbin/chroot $tpdir /bin/su - $mac -c ";
[681]2114        } elsif ($vetype eq "schroot") {
2115            $shcmd = "schroot $tp -u $mac -- ";
2116        }
[1179]2117        $cpcmd = "sudo /bin/cp -r ";
[681]2118        # We need to get the home dir of the target account to deliver in the right place
[1541]2119        open(PASS,"$tpdir/etc/passwd") || die "Unable to open $tpdir/etc/passwd: $!";
[681]2120        my $homedir = "";
2121        while (<PASS>) {
2122            my ($c1,$c2,$c3,$c4,$c5,$c6,$c7) = split(/:/);
2123            $homedir = $c6 if ($c1 =~ /^$mac$/);
2124            pb_log(3,"Homedir: $homedir - account: $c6\n");
2125        }
2126        close(PASS);
2127        $cptarget = "$tpdir/$homedir/$tdir";
[773]2128        if ($cmt eq "VEbuild") {
[681]2129            $cp2target = "$tpdir/$homedir/$bdir";
2130        }
2131        pb_log(2,"On VE using $cptarget as target dir to copy to\n");
[1374]2132    } elsif ($cmt =~ /^CPAN/) {
[1382]2133        my $ftpput = pb_check_req("ncftpput",1);
2134        my $ftpget = pb_check_req("wget",1);
[1374]2135        my ($cpanuser,$cpanpasswd) = pb_conf_get("cpanuser","cpanpasswd");
2136        my ($cpansubdir) = pb_conf_get_if("cpansubdir");
2137        $shcmd = "$ftpget --post-data \'HIDDENNAME=".$cpanuser;
2138        $shcmd .= "&user=".$cpanuser;
2139        $shcmd .= "&password=".$cpanpasswd;
2140        $shcmd .= "&SUBMIT_pause99_add_uri_upload=\"Upload the checked files\"";
2141        $shcmd .= "&pause99_add_uri_subdirtext=".$cpansubdir if (defined $cpansubdir);
2142        foreach my $s (split(/ /,$src)) {
2143            $shcmd .= "&pause99_add_uri_upload=".basename($s);
2144        }
2145        $shcmd .= "'";
2146        $cpcmd = "$ftpput $host $dir";
2147        $cptarget = "CPAN";
2148    } else {
2149        my $keyfile = pb_ssh_get(0);
[1382]2150        my $sshcmd = pb_check_req("ssh",1);
2151        my $scpcmd = pb_check_req("scp",1);
[1374]2152        $shcmd = "$sshcmd -i $keyfile -q -o UserKnownHostsFile=/dev/null -p $nport $mac";
2153        $cpcmd = "$scpcmd -i $keyfile -p -o UserKnownHostsFile=/dev/null -P $nport";
2154        $cptarget = "$mac:$tdir";
2155        if ($cmt =~ /^(V|R)Mbuild/) {
2156            $cp2target = "$mac:$bdir";
2157        }
[320]2158    }
[1374]2159   
[471]2160    my $logres = "";
2161    # Do not touch when just announcing
[1374]2162    if (($cmt ne "Announce") && ($cmt ne "CPAN")) {
[908]2163        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");
[471]2164    } else {
2165        $logres = "> ";
2166    }
[320]2167    pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget");
[444]2168
[681]2169    # For VE we need to change the owner manually
[772]2170    if ($cmt =~ /^VE/) {
[681]2171        pb_system("$shcmd \"sudo chown -R $mac $tdir\"","Adapt owner in $tdir to $mac");
2172    }
2173
[1140]2174    # Use the right script name depending on context
2175    my $pbscript;
[1189]2176    if (($cmt =~ /^(V[EM]|RM)/) || ($cmt =~ /Packages/)){
[1140]2177        $pbscript = "pbscript.$$";
2178    } else {
2179        $pbscript = "pbscript";
2180    }
2181
[1374]2182    # It's already ready for CPAN
[1383]2183    my $shcmdbase = $shcmd;
[1374]2184    if ($cmt !~ /^CPAN/) {
[1383]2185        $shcmd .= " \"echo \'cd $tdir ; if [ -x $pbscript ]; then ./$pbscript; fi ; rm -f ./$pbscript\' | bash\"";
[1374]2186    }
[1386]2187    my $cmdverb = "verbose";
[1388]2188    if (($cmt eq "Announce") || ($cmt eq "CPAN")) {
[1386]2189        $cmdverb = undef;
2190    }
2191    pb_system("$shcmd","Executing pbscript on $cptarget if needed",$cmdverb);
[1176]2192    if ($cmt =~ /^(V[EM]|RM)build/) {
2193        # Get back info on pkg produced, compute their name and get them from the VM/RM
[1189]2194        pb_system("$cpcmd $cp2target/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$ 2> /dev/null","Get package names in $cp2target");
[681]2195        # For VE we need to change the owner manually
[772]2196        if ($cmt eq "VEbuild") {
[1138]2197            pb_system("sudo chown $UID $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$","Adapt owner in $tdir to $UID");
[681]2198        }
[1138]2199        if (not -f "$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$") {
[1176]2200            pb_log(0,"Problem with VM/RM $v on $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$");
[1156]2201        } else {
2202            open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$";
2203            my $src = <KEEP>;
2204            chomp($src);
2205            close(KEEP);
2206            unlink("$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$");
[1138]2207
[1156]2208            $src =~ s/^ *//;
[1179]2209            pb_mkdir_p("$ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
[1156]2210            # Change pgben to make the next send2target happy
2211            my $made = "";
2212   
[1176]2213            # For VM/RM we don't want shell expansion to hapen locally but remotely
[1156]2214            my $delim = '\'';
2215            if ($cmt =~ /^VEbuild/) {
2216                # For VE we need to support shell expansion locally
2217                $delim = "";
2218            }   
[1138]2219
[1189]2220            open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") || die "Unable to write $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
[1156]2221            foreach my $p (split(/ +/,$src)) {
2222                my $j = basename($p);
[1179]2223                pb_system("$cpcmd $cp2target/$delim$p$delim $ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'} 2> /dev/null","Recovery of package $j in $ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
2224                $made="$made $pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/$j"; # if (($pbos->{'type'} ne "rpm") || ($j !~ /.src.rpm$/));
[1156]2225            }
2226            print KEEP "$made\n";
2227            close(KEEP);
[1383]2228            pb_system("$shcmdbase \"rm -rf $tdir $bdir\"","$cmt cleanup");
[1138]2229
[1156]2230            # Sign packages locally
[1278]2231            pb_sign_pkgs($pbos,$made);
[1156]2232
2233            # We want to send them to the ssh account so overwrite what has been done before
2234            undef $pbaccount;
2235            pb_log(2,"Before sending pkgs, vmexist: $vmexist, vmpid: $vmpid\n");
[1179]2236            pb_send2target("Packages",$pbos->{'name'}."-".$pbos->{'version'}."-".$pbos->{'arch'},$vmexist,$vmpid);
2237            pb_rm_rf("$ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
[623]2238        }
[108]2239    }
[1425]2240    unlink("$ENV{'PBDESTDIR'}/pbscript.$$") if ((($cmt =~ /^(V[ME]|RM)/) || ($cmt =~ /Packages/)) && ($pbkeep eq 0));
[1139]2241
[442]2242    pb_log(2,"Before halt, vmexist: $vmexist, vmpid: $vmpid\n");
[772]2243    if ((! $vmexist) && ($cmt =~ /^VM/)) {
[748]2244        # If in setupvm then takes a snapshot just before halting
2245        if ($snapme != 0) {
2246            my ($vmmonport,$vmtype) = pb_conf_get("vmmonport","vmtype");
2247            # For monitoring control
2248            if ((($vmtype->{$ENV{'PBPROJ'}}) eq "kvm") || (($vmtype->{$ENV{'PBPROJ'}}) eq "qemu")) {
[1153]2249                eval
2250                {
[804]2251                require Net::Telnet;
[1153]2252                Net::Telnet->import();
2253                };
2254                if ($@) {
2255                    # Net::Telnet not found
2256                    pb_log(1,"ADVISE: Install Net::Telnet to benefit from monitoring control and snapshot feature.\nWARNING: No snapshot created");
2257                } else {
2258                    my $t = new Net::Telnet (Timeout => 120, Host => "localhost", Port => $vmmonport->{$ENV{'PBPROJ'}}) || die "Unable to dialog on the monitor";
2259                    # move to monitor mode
2260                    my @lines = $t->cmd("c");
2261                    # Create a snapshot named pb
2262                    @lines = $t->cmd("savevm pb");
2263                    # Write the new status in the VM
2264                    @lines = $t->cmd("commit all");
2265                    # End
2266                    @lines = $t->cmd("quit");
2267                }
[748]2268            }
2269        }
[914]2270        my $hoption = "-p";
[1197]2271        my $hpath = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-halt"));
[1194]2272        # Solaris doesn't support -p of halt
[1177]2273        if ($pbos->{'type'} eq "pkg") {
[1091]2274            $hoption = "" ;
2275        }
[1383]2276        pb_system("$shcmdbase \"sudo $hpath $hoption \"; $tm ; echo \'if [ -d /proc/$vmpid ]; then kill -9 $vmpid; fi \' | bash ; sleep 10","VM $v halt (pid $vmpid)");
[442]2277    }
[772]2278    if (($cmt =~ /^VE/) && ($snapme != 0)) {
[1179]2279        my $tpdir = "$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}";
2280        pb_system("sudo tar cz -C $tpdir -f $vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz .","Creating a snapshot of $tpdir");
[752]2281    }
[9]2282}
[16]2283
[320]2284sub pb_script2v {
[142]2285    my $pbscript=shift;
[320]2286    my $vtype=shift;
[1138]2287    my $pbforce=shift || 0; # Force stop of VM. Default not.
[1176]2288    my $vm1=shift || undef; # Only that VM/VE/RM to treat. Default all.
[1138]2289    my $snapme=shift || 0;  # Do we have to create a snapshot. Default not.
[442]2290    my $vm;
2291    my $all;
[141]2292
[767]2293    pb_log(2,"DEBUG: pb_script2v($pbscript,$vtype,$pbforce,".Dumper($vm1).",$snapme)\n");
[1176]2294    # Prepare the script to be executed on the VM/VE/RM
[1138]2295    # in $ENV{'PBDESTDIR'}/pbscript.$$
2296    if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript.$$")) {
2297        copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript.$$";
2298        chmod 0755,"$ENV{'PBDESTDIR'}/pbscript.$$";
[142]2299    }
[141]2300
[442]2301    if (not defined $vm1) {
[772]2302        ($vm,$all) = pb_get2v($vtype);
[442]2303    } else {
2304        @$vm = ($vm1);
2305    }
[320]2306    my ($vmexist,$vmpid) = (undef,undef);
[142]2307
[141]2308    foreach my $v (@$vm) {
[968]2309        # Launch VM/VE
2310        ($vmexist,$vmpid) = pb_launchv($vtype,$v,0,$snapme,$pbsnap);
[755]2311
[320]2312        if ($vtype eq "vm") {
[442]2313            pb_log(2,"DEBUG: After pb_launchv, vmexist: $vmexist, vmpid: $vmpid\n");
[141]2314
[1176]2315            # Skip that VM/RM if something went wrong
[442]2316            next if (($vmpid == 0) && ($vmexist == 0));
2317
2318            # If force stopping the VM then reset vmexist
[748]2319            if ($pbforce == 1) {
[442]2320                $vmpid = $vmexist;
2321                $vmexist = 0;
2322            }
[670]2323        } else {
2324            #VE
2325            $vmexist = 0;
2326            $vmpid = 0;
[320]2327        }
[274]2328
[1176]2329        # Gather all required files to send them to the VM/VE/RM
[320]2330        # and launch the build through pbscript
[442]2331        pb_log(2,"DEBUG: Before send2target, vmexist: $vmexist, vmpid: $vmpid\n");
[748]2332        pb_send2target(uc($vtype)."Script","$v",$vmexist,$vmpid,$snapme);
[169]2333
[142]2334    }
2335}
2336
[320]2337sub pb_launchv {
2338    my $vtype = shift;
2339    my $v = shift;
[1176]2340    my $create = shift || 0;        # By default do not create a VM/VE/RM
2341    my $snapme = shift || 0;        # By default do not snap a VM/VE/RM
[1349]2342    my $usesnap = shift || 1;       # By default study the usage of the snapshot feature of VM/VE/RM   
[310]2343
[773]2344    # If creation or snapshot creation mode, no snapshot usable
2345    if (($create == 1) || ($snapme == 1)) {
2346        $usesnap = 0;
2347    }
2348
2349    pb_log(2,"DEBUG: pb_launchv($vtype,$v,$create,$snapme,$usesnap)\n");
[1176]2350    die "No VM/VE/RM defined, unable to launch" if (not defined $v);
[320]2351    # Keep only the first VM in case many were given
[1537]2352    if ($v =~ /,/) {
2353        pb_log(0,"WARNING: pruning to just the first of several vms listed ($v)\n");
2354        $v =~ s/,.*//;
2355    }
[310]2356
[1179]2357    my $pbos = pb_distro_get_context($v);
[1348]2358   
[320]2359    # Launch the VMs/VEs
2360    if ($vtype eq "vm") {
2361        die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0));
[310]2362
[1540]2363        my ($ptr,$ptr2,$vmpath,$vmport,$vms) = pb_conf_get("vmtype","vmcmd","vmpath","vmport","vmsize");
2364        my ($vmopt,$vmmm,$vmtmout,$vmsnap,$vmbuildtm,$vmmonport) = pb_conf_get_if("vmopt","vmmem","vmtmout","vmsnap","vmbuildtm","vmmonport");
[1249]2365        my $vmsize = pb_distro_get_param($pbos,$vms);
[320]2366
2367        my $vmtype = $ptr->{$ENV{'PBPROJ'}};
[1072]2368        my $vmcmd = $ptr2->{$ENV{'PBPROJ'}};
[1124]2369
2370        if (defined $opts{'g'}) {
2371            if (($vmtype eq "kvm") || ($vmtype eq "qemu")) {
[1158]2372                $ENV{'PBVMOPT'} = "--nographic";
[1124]2373            }
2374        }
[320]2375        if (not defined $ENV{'PBVMOPT'}) {
2376            $ENV{'PBVMOPT'} = "";
[310]2377        }
[639]2378        # Save the current status for later restoration
2379        $ENV{'PBOLDVMOPT'} = $ENV{'PBVMOPT'};
[483]2380        # Set a default timeout of 2 minutes
2381        if (not defined $ENV{'PBVMTMOUT'}) {
2382            $ENV{'PBVMTMOUT'} = "120";
2383        }
2384        if (defined $vmopt->{$v}) {
2385            $ENV{'PBVMOPT'} .= " $vmopt->{$v}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$v}/);
2386        } elsif (defined $vmopt->{$ENV{'PBPROJ'}}) {
[320]2387            $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/);
2388        }
[773]2389
[1143]2390        # How much memory to allocate for VMs
[1540]2391        if (defined $vmmm) {
2392            my $vmmem = pb_distro_get_param($pbos,$vmmm);
2393            if (defined $vmmem) {
2394                $ENV{'PBVMOPT'} .= " -m $vmmem";
2395            }
[1143]2396        }
2397
[773]2398        # Are we allowed to use snapshot feature
2399        if ($usesnap == 1) {
[748]2400            if ((defined $vmsnap->{$v}) && ($vmsnap->{$v} =~ /true/i)) {
[1070]2401                $ENV{'PBVMOPT'} .= " -snapshot";
[748]2402            } elsif ((defined $vmsnap->{$ENV{'PBPROJ'}}) && ($vmsnap->{$ENV{'PBPROJ'}} =~ /true/i)) {
[1070]2403                $ENV{'PBVMOPT'} .= " -snapshot";
[748]2404            } elsif ($pbsnap eq 1) {
[1070]2405                $ENV{'PBVMOPT'} .= " -snapshot";
[748]2406            }
[767]2407        } 
2408        if ($snapme != 0) {
[748]2409            if (($vmtype eq "kvm") || ($vmtype eq "qemu")) {
[1138]2410                # Configure the monitoring to automate the creation of the 'pb' snapshot
[1540]2411                $ENV{'PBVMOPT'} .= " -serial mon:telnet::$vmmonport->{$ENV{'PBPROJ'}},server,nowait" if ((defined $vmmonport) && (defined $vmmonport->{$ENV{'PBPROJ'}}));
[773]2412                # In that case no snapshot call needed
[1070]2413                $ENV{'PBVMOPT'} =~ s/ -snapshot//;
[748]2414            }
2415        }
[483]2416        if (defined $vmtmout->{$v}) {
2417            $ENV{'PBVMTMOUT'} = $vmtmout->{$v};
2418        } elsif (defined $vmtmout->{$ENV{'PBPROJ'}}) {
2419            $ENV{'PBVMTMOUT'} = $vmtmout->{$ENV{'PBPROJ'}};
2420        }
[1179]2421        my $nport = pb_get_port($vmport,$pbos,$vtype);
[320]2422   
2423        my $cmd;
2424        my $vmm;        # has to be used for pb_check_ps
[677]2425        if (($vmtype eq "qemu") || ($vmtype eq "kvm")) {
2426            $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu";
[792]2427            if (($create != 0) || (defined $iso)) {
[677]2428                $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d";
[320]2429            }
[748]2430            # Always redirect the network and always try to use a 'pb' snapshot
[1340]2431            #$cmd = "$vmcmd $ENV{'PBVMOPT'} -net user,hostfwd=tcp:$nport:10.0.2.15:22 -loadvm pb $vmm"
[1381]2432            $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm"
[320]2433        } elsif ($vmtype eq "xen") {
2434        } elsif ($vmtype eq "vmware") {
[310]2435        } else {
[320]2436            die "VM of type $vmtype not supported. Report to the dev team";
[310]2437        }
[639]2438        # Restore the ENV VAR Value
[641]2439        $ENV{'PBVMOPT'} = $ENV{'PBOLDVMOPT'};
[639]2440
[320]2441        my ($tmpcmd,$void) = split(/ +/,$cmd);
2442        my $vmexist = pb_check_ps($tmpcmd,$vmm);
2443        my $vmpid = 0;
2444        if (! $vmexist) {
2445            if ($create != 0) {
[653]2446                die("Found an existing Virtual machine $vmm. Won't overwrite") if (-r $vmm);
[677]2447                if (($vmtype eq "qemu") || ($vmtype eq "xen") || ($vmtype eq "kvm")) {
[1127]2448                    my $command = pb_check_req("qemu-img",0);
[1249]2449                    pb_system("$command create -f qcow2 $vmm $vmsize","Creating the QEMU VM");
[320]2450                } elsif ($vmtype eq "vmware") {
2451                } else {
2452                }
2453            }
2454            if (! -f "$vmm") {
2455                pb_log(0,"Unable to find VM $vmm\n");
2456            } else {
[1153]2457                # Is the SSH port free? if not kill the existing process using it after a build timeout period
2458                my $vmssh = pb_check_ps($tmpcmd,"tcp:$nport:10.0.2.15:22");
2459                if ($vmssh) {
2460                    my $buildtm = $ENV{'PBVMTMOUT'};
2461                    if (defined $vmbuildtm->{$v}) {
2462                        $buildtm = $vmbuildtm->{$v};
2463                    } elsif (defined $vmbuildtm->{$ENV{'PBPROJ'}}) {
2464                        $buildtm = $vmbuildtm->{$ENV{'PBPROJ'}};
2465                    }
2466
2467                    sleep $buildtm;
2468                    pb_log(0,"WARNING: Killing the process ($vmssh) using port $nport (previous failed VM ?)\n");
2469                    kill 15,$vmssh;
[1154]2470                    # Let it time to exit
2471                    sleep 5;
[1153]2472                }
[320]2473                pb_system("$cmd &","Launching the VM $vmm");
[1540]2474                # Using system allows to kill it externaly if needed,sosupport that in the call
2475                pb_system("sleep $ENV{'PBVMTMOUT'}","Waiting $ENV{'PBVMTMOUT'} s for VM $v to come up",undef,1);
[320]2476                $vmpid = pb_check_ps($tmpcmd,$vmm);
[357]2477                pb_log(0,"VM $vmm launched (pid $vmpid)\n");
[320]2478            }
[310]2479        } else {
[320]2480            pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n");
[310]2481        }
[442]2482        pb_log(2,"DEBUG: pb_launchv returns ($vmexist,$vmpid)\n");
[320]2483        return($vmexist,$vmpid);
[1176]2484    } elsif ($vtype eq "ve") {
[1360]2485        # Force the creation of the VE and no snapshot usable
[1388]2486        pb_ve_launch($v,$create,$usesnap);
[1176]2487    } else {
2488        # RM here
2489        # Get distro context
[1177]2490        my $pbos = pb_distro_get_context($v);
[1176]2491
2492        # Get RM context
2493        my ($ptr,$rmpath) = pb_conf_get("rmtype","rmpath");
2494
2495        # Nothing more to do for RM. No real launch
2496        # For the moment we support the RM is already running
2497        # For ProLiant may be able to power them on if needed later on as an example.
[141]2498    }
2499}
[142]2500
[639]2501# Return string for date synchro
[772]2502sub pb_date2v {
[639]2503
2504my $vtype = shift;
[1216]2505my $pbos = shift;
[639]2506
[986]2507my ($ntp) = pb_conf_get_if($vtype."ntp");
2508my $vntp = $ntp->{$ENV{'PBPROJ'}} if (defined $ntp);
[1221]2509my $ntpline = undef;
[639]2510
2511if (defined $vntp) {
[1221]2512    # ntp command depends on pbos
2513    my $vntpcmd = pb_distro_get_param($pbos,pb_conf_get($vtype."ntpcmd"));
[652]2514    $ntpline = "sudo $vntpcmd $vntp";
[639]2515}
2516# Force new date to be in the future compared to the date
2517# of the host by adding 1 minute
2518my @date=pb_get_date();
2519$date[1]++;
2520my $upddate = strftime("%m%d%H%M%Y", @date);
[1179]2521my $dateline = "sudo /bin/date $upddate";
[1190]2522if (defined $ntpline) {
2523    return($ntpline);
2524} else {
2525    return($dateline);
[639]2526}
[1190]2527}
[639]2528
[320]2529sub pb_build2v {
[118]2530
[320]2531my $vtype = shift;
[772]2532my $action = shift || "build";
[142]2533
[772]2534my ($v,$all) = pb_get2v($vtype);
[320]2535
2536# Send tar files when we do a global generation
[772]2537pb_build2ssh() if (($all == 1) && ($action eq "build"));
[320]2538
[1143]2539# Adapt // mode to memory size
2540$pbparallel = pb_set_parallel($vtype);
2541
[320]2542my ($vmexist,$vmpid) = (undef,undef);
[1176]2543my $pm;
2544if (defined $pbparallel) {
2545    $pm = new Parallel::ForkManager($pbparallel);
[320]2546
[1176]2547    # Set which port the VM/RM will use to communicate
2548    $pm->run_on_start(\&pb_set_port);
2549}
[1143]2550
2551my $counter = 0;
[320]2552foreach my $v (@$v) {
[1143]2553    $counter++;
[1153]2554    # Modulo 2 * pbparallel (to avoid synchronization problems)
[1176]2555    $counter = 1 if ((defined $pbparallel) && ($counter > 2 * $pbparallel));
[1143]2556    $pm->start($counter) and next if (defined $pbparallel);
[1176]2557    # Prepare the script to be executed on the VM/VE/RM
[1138]2558    # in $ENV{'PBDESTDIR'}/pbscript.$$
2559    open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript.$$";
[652]2560    print SCRIPT "#!/bin/bash\n";
[721]2561
2562    # Transmit the verbosity level to the virtual env/mach.
2563    my $verbose = "";
2564    my $i = 0;                          # minimal debug level
2565    while ($i lt $pbdebug) {
2566        $verbose .= "-v ";
2567        $i++;
2568    }
2569    # Activate script verbosity if at least 2 for pbdebug
2570    print SCRIPT "set -x\n" if ($i gt 1);
2571    # Quiet if asked to be so on the original system
2572    $verbose = "-q" if ($pbdebug eq -1);
2573
[652]2574    print SCRIPT "echo ... Execution needed\n";
2575    print SCRIPT "# This is in directory delivery\n";
2576    print SCRIPT "# Setup the variables required for building\n";
2577    print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n";
[686]2578
[772]2579    if ($action eq "build") {
2580        print SCRIPT "# Preparation for pb\n";
2581        print SCRIPT "mv .pbrc \$HOME\n";
2582        print SCRIPT "cd ..\n";
2583    }
2584
[686]2585    # VE needs a good /proc
[687]2586    if ($vtype eq "ve") {
[1179]2587        print SCRIPT "sudo /bin/mount -t proc /proc /proc\n";
[686]2588    }
[652]2589
[1216]2590    # Get distro context
2591    my $pbos = pb_distro_get_context($v);
2592   
2593    my $ntpline = pb_date2v($vtype,$pbos);
[652]2594    print SCRIPT "# Time sync\n";
[725]2595    print SCRIPT "echo 'setting up date with '";
[1190]2596    print SCRIPT "echo $ntpline\n";
2597    print SCRIPT "$ntpline\n";
[721]2598    # Use potential local proxy declaration in case we need it to download repo, pkgs, ...
2599    if (defined $ENV{'http_proxy'}) {
2600        print SCRIPT "export http_proxy=\"$ENV{'http_proxy'}\"\n";
2601    }
[652]2602
[721]2603    if (defined $ENV{'ftp_proxy'}) {
2604        print SCRIPT "export ftp_proxy=\"$ENV{'ftp_proxy'}\"\n";
[652]2605    }
2606
[772]2607    # Get list of packages to build/test and get some ENV vars as well
2608    my $ptr = pb_get_pkg();
2609    @pkgs = @$ptr;
2610    my $p = join(' ',@pkgs) if (@pkgs);
2611    print SCRIPT "export PBPROJVER=$ENV{'PBPROJVER'}\n";
2612    print SCRIPT "export PBPROJTAG=$ENV{'PBPROJTAG'}\n";
2613    print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n";
[721]2614
2615    # We may need to do some other tasks before building. Read a script here to finish setup
[772]2616    if (-x "$ENV{'PBDESTDIR'}/pb$vtype".".pre") {
2617        print SCRIPT "# Special pre-instructions to be launched\n";
2618        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype".".pre");
[721]2619    }
2620
[772]2621    if (-x "$ENV{'PBDESTDIR'}/pb$vtype"."$action.pre") {
2622        print SCRIPT "# Special pre-$action instructions to be launched\n";
2623        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype"."$action.pre");
2624    }
2625
2626    print SCRIPT "# $action\n";
2627    print SCRIPT "echo $action"."ing packages on $vtype...\n";
2628
2629    if (($action eq "test") && (! -x "$ENV{'PBDESTDIR'}/pbtest")) {
2630            die "No test script ($ENV{'PBDESTDIR'}/pbtest) found when in test mode. Aborting ...";
2631    }
2632    print SCRIPT "pb $verbose -p $ENV{'PBPROJ'} $action"."2pkg $p\n";
2633
[687]2634    if ($vtype eq "ve") {
[1179]2635        print SCRIPT "sudo /bin/umount /proc\n";
[686]2636    }
[721]2637
2638    # We may need to do some other tasks after building. Read a script here to exit properly
[772]2639    if (-x "$ENV{'PBDESTDIR'}/pb$vtype"."$action.post") {
2640        print SCRIPT "# Special post-$action instructions to be launched\n";
2641        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype"."$action.post");
[721]2642    }
2643
[772]2644    if (-x "$ENV{'PBDESTDIR'}/pb$vtype".".post") {
2645        print SCRIPT "# Special post-instructions to be launched\n";
2646        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype".".post");
2647    }
2648
[652]2649    close(SCRIPT);
[1138]2650    chmod 0755,"$ENV{'PBDESTDIR'}/pbscript.$$";
[652]2651   
[1176]2652    # Launch the VM/VE/RM
[755]2653    ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
2654
[1139]2655
[320]2656    if ($vtype eq "vm") {
[1143]2657        # Skip that VM if something went wrong
[1139]2658        if (($vmpid == 0) && ($vmexist == 0)) {
2659            $pm->finish if (defined $pbparallel);
2660            next;
2661        }
[658]2662    } else {
[1176]2663        # VE/RM
[658]2664        $vmexist = 0;
2665        $vmpid = 0;
[118]2666    }
[320]2667    # Gather all required files to send them to the VM/VE
[347]2668    # and launch the build through pbscript
[357]2669    pb_log(2,"Calling send2target $vtype,$v,$vmexist,$vmpid\n");
[772]2670    pb_send2target(uc($vtype).$action,"$v",$vmexist,$vmpid);
[1139]2671    $pm->finish if (defined $pbparallel);
[105]2672}
[1176]2673$pm->wait_all_children if (defined $pbparallel);
[320]2674}
[105]2675
[262]2676
[739]2677sub pb_clean {
2678
2679    my $sleep=10;
2680    die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
2681    die "Unable to get env var PBBUILDDIR" if (not defined $ENV{'PBBUILDDIR'});
2682    pb_log(0,"We will now wait $sleep s before removing both directories\n$ENV{'PBDESTDIR'} and $ENV{'PBBUILDDIR'}.\nPlease break me if this is wrong\n");
2683    sleep $sleep;
2684    pb_rm_rf($ENV{'PBDESTDIR'});
2685    pb_rm_rf($ENV{'PBBUILDDIR'});
2686}
2687
[199]2688sub pb_newver {
2689
[204]2690    die "-V Version parameter needed" if ((not defined $newver) || ($newver eq ""));
[340]2691
[366]2692    # Need this call for PBDIR
2693    my ($scheme2,$uri) = pb_cms_init($pbinit);
[361]2694
[898]2695    my ($pbconf,$pburl) = pb_conf_get("pbconfurl","pburl");
[366]2696    $uri = $pbconf->{$ENV{'PBPROJ'}};
2697    my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
2698
[361]2699    # Checking CMS repositories status
[366]2700    ($scheme2, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}});
[340]2701
2702    if ($scheme !~ /^svn/) {
[199]2703        die "Only SVN is supported at the moment";
2704    }
[483]2705
[1469]2706    my $res = pb_vcs_isdiff($scheme,$ENV{'PBROOTDIR'});
[361]2707    die "ERROR: No differences accepted in CMS for $ENV{'PBROOTDIR'} before creating a new version" if ($res != 0);
[358]2708
[1469]2709    $res = pb_vcs_isdiff($scheme2,$ENV{'PBDIR'});
[361]2710    die "ERROR: No differences accepted in CMS for $ENV{'PBDIR'} before creating a new version" if ($res != 0);
[358]2711
2712    # Tree identical between PBCONFDIR and PBROOTDIR. The delta is what
2713    # we want to get for the root of the new URL
2714
[1381]2715    my $oldver = $ENV{'PBROOTDIR'};
2716    $oldver =~ s|^$ENV{'PBCONFDIR'}||;
[358]2717
[1381]2718    pb_log(2, "PBCONFDIR: $ENV{'PBCONFDIR'}\nPBROOTDIR: $ENV{'PBROOTDIR'}\n");
2719
2720    my $newurl = "$uri/$newver";
[366]2721    # Should probably use projver in the old file
[1381]2722    my $oldvertxt= basename($oldver);
2723    my $newvertxt = basename($newver);
[361]2724
[366]2725    # Duplicate and extract project-builder part
[1381]2726    pb_log(2,"Copying $uri/$oldver to $newurl\n");
[1469]2727    pb_vcs_copy($scheme,"$uri/$oldver",$newurl);
[1381]2728    pb_log(2,"Checkout $newurl to $ENV{'PBCONFDIR'}/$newver\n");
[1469]2729    pb_vcs_up($scheme,"$ENV{'PBCONFDIR'}");
[361]2730
[366]2731    # Duplicate and extract project
[1381]2732    my $newurl2 = "$pburl->{$ENV{'PBPROJ'}}/$newver";
[366]2733
[1381]2734    pb_log(2,"Copying $pburl->{$ENV{'PBPROJ'}}/$oldver to $newurl2\n");
[1469]2735    pb_vcs_copy($scheme2,"$pburl->{$ENV{'PBPROJ'}}/$oldver",$newurl2);
[366]2736
[1381]2737    my $tmp = $ENV{'PBDIR'};
2738    $tmp =~ s|$oldver$||;
2739    pb_log(2,"Checkout $newurl2 to $tmp/$newver\n");
[1469]2740    pb_vcs_up($scheme2,"$tmp");
[1381]2741
[361]2742    # Update the .pb file
[1381]2743    open(FILE,"$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb";
2744    open(OUT,"> $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new";
[208]2745    while(<FILE>) {
[1420]2746        if (/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldvertxt$/) {
2747            s/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldvertxt$/projver $ENV{'PBPROJ'} = $newvertxt/;
[1381]2748            pb_log(0,"Changing projver from $oldvertxt to $newvertxt in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n");
2749        }
2750        if (/^testver/) {
2751            s/^testver/#testver/;
2752            pb_log(0,"Commenting testver in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n") if (/^testver/);
2753        }
2754        if (/^delivery/) {
[1420]2755            my $txt = $_;
2756            chomp($txt);
2757            pb_log(0,"Please check delivery ($txt) in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n");
[1381]2758        }
[211]2759        print OUT $_;
[208]2760    }
2761    close(FILE);
[211]2762    close(OUT);
[1381]2763    rename("$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new","$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb");
[363]2764
[479]2765    # Checking pbcl files
2766    foreach my $f (<$ENV{'PBROOTDIR'}/*/pbcl>) {
[590]2767        # Compute new pbcl file
2768        my $f2 = $f;
[1381]2769        $f2 =~ s|$ENV{'PBROOTDIR'}|$ENV{'PBCONFDIR'}/$newver/|;
[479]2770        open(PBCL,$f) || die "Unable to open $f";
2771        my $foundnew = 0;
2772        while (<PBCL>) {
[1381]2773            $foundnew = 1 if (/^$newvertxt \(/);
[479]2774        }
2775        close(PBCL);
[590]2776        open(OUT,"> $f2") || die "Unable to write to $f2: $!";
[479]2777        open(PBCL,$f) || die "Unable to open $f";
2778        while (<PBCL>) {
[1381]2779            print OUT "$_" if (not /^$oldvertxt \(/);
2780            if ((/^$oldvertxt \(/) && ($foundnew == 0)) {
2781                print OUT "$newvertxt ($pbdate)\n";
[479]2782                print OUT "- TBD\n";
2783                print OUT "\n";
[1381]2784                pb_log(0,"WARNING: version $newvertxt not found in $f so added to $f2...\n") if ($foundnew == 0);
[479]2785            }
2786        }
2787        close(OUT);
2788        close(PBCL);
2789    }
2790
[1381]2791    pb_log(2,"Checkin $ENV{'PBCONFDIR'}/$newver\n");
2792    pb_cms_checkin($scheme,"$ENV{'PBCONFDIR'}/$newver",undef);
[199]2793}
2794
[293]2795#
[1176]2796# Return the list of VMs/VEs/RMs we are working on
[105]2797# $all is a flag to know if we return all of them
2798# or only some (if all we publish also tar files in addition to pkgs
2799#
[772]2800sub pb_get2v {
[91]2801
[320]2802my $vtype = shift;
2803my @v;
[105]2804my $all = 0;
[320]2805my $pbv = 'PBV';
[1176]2806my $vlist = $vtype."list";
[91]2807
[320]2808# Get VM/VE list
2809if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) {
2810    my ($ptr) = pb_conf_get($vlist);
2811    $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}};
[105]2812    $all = 1;
[91]2813}
[320]2814pb_log(2,"$vtype: $ENV{$pbv}\n");
2815@v = split(/,/,$ENV{$pbv});
2816return(\@v,$all);
[91]2817}
2818
[1541]2819# This function creates a giant script to configure a particular VM/VE/RM, it then copies the
2820# script to the target.
2821
[1176]2822# Function to create a potentialy missing pb account on the VM/VE/RM, and adds it to sudo
2823# Needs to use root account to connect to the VM/VE/RM
[320]2824# pb will take your local public SSH key to access
[1176]2825# the pb account in the VM/VE/RM later on if needed
[772]2826sub pb_setup2v {
[320]2827
2828my $vtype = shift;
[1140]2829my $sbx = shift || undef;
[320]2830
[772]2831my ($vm,$all) = pb_get2v($vtype);
[353]2832
[346]2833# Script generated
2834my $pbscript = "$ENV{'PBDESTDIR'}/setupv";
[320]2835
[1143]2836# Adapt // mode to memory size
2837$pbparallel = pb_set_parallel($vtype);
2838
[1176]2839my $pm;
2840if (defined $pbparallel) {
2841    $pm = new Parallel::ForkManager($pbparallel);
[1143]2842
[1176]2843    # Set which port the VM/RM will use to communicate
2844    $pm->run_on_start(\&pb_set_port);
2845}
[1143]2846
2847my $counter = 0;
[652]2848foreach my $v (@$vm) {
[1143]2849    $counter++;
2850    # Modulo pbparallel
[1176]2851    $counter = 1 if ((defined $pbparallel) && ($counter > $pbparallel));
[1143]2852    $pm->start($counter) and next if (defined $pbparallel);
2853
[891]2854    # Get distro context
[1177]2855    my $pbos = pb_distro_get_context($v);
[891]2856   
[1216]2857    # Deal with date sync.
2858    my $ntpline = pb_date2v($vtype,$pbos);
2859
[1176]2860    # Name of the account to deal with for VM/VE/RM
[353]2861    # Do not use the one passed potentially with -a
2862    my ($pbac) = pb_conf_get($vtype."login");
[354]2863    my ($key,$zero0,$zero1,$zero2);
[639]2864    my ($vmexist,$vmpid);
[346]2865
[1176]2866    # Prepare the script to be executed on the VM/VE/RM
[681]2867    # in $ENV{'PBDESTDIR'}/setupv
2868    open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
2869   
2870    print SCRIPT << 'EOF';
2871#!/usr/bin/perl -w
2872
2873use strict;
2874use File::Copy;
2875
2876# We should not need in this script more functions than what is provided
[1140]2877# by Base, Conf and Distribution to avoid problems at exec time.
[681]2878# They are appended at the end.
2879
[1156]2880# Define mandatory global vars
[681]2881our $pbdebug;
2882our $pbLOG;
2883our $pbsynmsg = "pbscript";
2884our $pbdisplaytype = "text";
2885our $pblocale = "";
2886pb_log_init($pbdebug, $pbLOG);
[1425]2887EOF
2888    print SCRIPT << "EOF";
2889pb_temp_init($pbkeep);
[1511]2890pb_conf_init("$ENV{'PBPROJ'}");
[681]2891
2892EOF
2893
[1176]2894    # Launch the VM/VE/RM - Usage of snapshot disabled
[773]2895    ($vmexist,$vmpid) = pb_launchv($vtype,$v,0,0,0);
[755]2896
[1156]2897    my $keyfile;
2898    my $nport;
2899    my $vmhost;
2900
[1255]2901    # Prepare the key to be used and transfered remotely
2902    $keyfile = pb_ssh_get(1);
2903       
[1176]2904    if ($vtype =~ /(v|r)m/) {
[1215]2905        my ($vmport);
2906        ($vmhost,$vmport) = pb_conf_get($vtype."host",$vtype."port");
[1179]2907        $nport = pb_get_port($vmport,$pbos,$vtype);
[347]2908   
[1176]2909        # Skip that VM/RM if something went wrong
[442]2910        next if (($vmpid == 0) && ($vmexist == 0));
[353]2911   
[354]2912        # Store the pub key part in a variable
2913        open(FILE,"$keyfile.pub") || die "Unable to open $keyfile.pub";
2914        ($zero0,$zero1,$zero2) = split(/ /,<FILE>);
2915        close(FILE);
2916
2917        $key = "\Q$zero1";
2918
[1105]2919        # We call true to avoid problems if SELinux is not activated, but chcon is present and returns in that case 1
2920        pb_system("cat $keyfile.pub | ssh -q -o UserKnownHostsFile=/dev/null -p $nport -i $keyfile root\@$vmhost->{$ENV{'PBPROJ'}} \"mkdir -p .ssh ; chmod 700 .ssh ; cat >> .ssh/authorized_keys ; chmod 600 .ssh/authorized_keys ; if [ -x /usr/bin/chcon ]; then /usr/bin/chcon -Rt home_ssh_t .ssh 2> /dev/null; /bin/true; fi\"","Copying local keys to $vtype. This may require the root password");
[1176]2921        # once this is done, we can do what we need on the VM/RM remotely
[681]2922    } elsif ($vtype eq "ve") {
[1029]2923        print SCRIPT << "EOF";
[940]2924# For VE we need a good null dev
2925pb_system("rm -f /dev/null; mknod /dev/null c 1 3; chmod 777 /dev/null");
[1541]2926
[681]2927# For VE we first need to mount some FS
2928pb_system("mount -t proc /proc /proc");
[346]2929
[354]2930EOF
[1541]2931    } else {
2932        die "Unknown virtual type $vtype";
[681]2933    }
[1029]2934
[1190]2935    if ($vtype =~ /(v|r)m/) {
[354]2936        print SCRIPT << 'EOF';
2937# Removes duplicate in .ssh/authorized_keys of our key if needed
2938#
2939my $file1="$ENV{'HOME'}/.ssh/authorized_keys";
2940open(PBFILE,$file1) || die "Unable to open $file1";
2941open(PBOUT,"> $file1.new") || die "Unable to open $file1.new";
2942my $count = 0;
2943while (<PBFILE>) {
[517]2944
[354]2945EOF
2946        print SCRIPT << "EOF";
2947    if (/ $key /) {
2948        \$count++;
2949    }
2950print PBOUT \$_ if ((\$count <= 1) || (\$_ !~ / $key /));
2951}
2952close(PBFILE);
2953close(PBOUT);
2954rename("\$file1.new",\$file1);
2955chmod 0600,\$file1;
[517]2956
[354]2957EOF
2958    }
2959    print SCRIPT << 'EOF';
2960
2961# Adds $pbac->{$ENV{'PBPROJ'}} as an account if needed
2962#
[346]2963my $file="/etc/passwd";
[320]2964open(PBFILE,$file) || die "Unable to open $file";
2965my $found = 0;
2966while (<PBFILE>) {
[346]2967EOF
[353]2968    print SCRIPT << "EOF";
2969    \$found = 1 if (/^$pbac->{$ENV{'PBPROJ'}}:/);
[346]2970EOF
[891]2971
[1176]2972# TODO: use an external parameter
[891]2973my $home = "/home";
2974# Solaris doesn't like that we use /home
[1177]2975$home = "/export/home" if ($pbos->{'type'} eq "pkg");
[891]2976
2977    print SCRIPT << "EOF";
[320]2978}
2979close(PBFILE);
2980
[891]2981if ( \$found == 0 ) {
2982    if ( ! -d "$home" ) {
2983        pb_mkdir_p("$home");
[320]2984    }
[346]2985EOF
[1179]2986    # TODO: Level of portability of these cmds ? Critical now for RM
[1255]2987    # TODO: Check existence before adding to avoid errors
[353]2988    print SCRIPT << "EOF";
[1051]2989pb_system("/usr/sbin/groupadd $pbac->{$ENV{'PBPROJ'}}","Adding group $pbac->{$ENV{'PBPROJ'}}");
2990pb_system("/usr/sbin/useradd -g $pbac->{$ENV{'PBPROJ'}} -m -d $home/$pbac->{$ENV{'PBPROJ'}} $pbac->{$ENV{'PBPROJ'}}","Adding user $pbac->{$ENV{'PBPROJ'}} (group $pbac->{$ENV{'PBPROJ'}} - home $home/$pbac->{$ENV{'PBPROJ'}})");
[427]2991}
[661]2992EOF
[320]2993
[1176]2994    # Copy the content of our local conf file to the VM/VE/RM
[891]2995    my $content = pb_get_content(pb_distro_conffile());
2996    print SCRIPT << "EOF";
2997    #
2998    # Create a temporary local conf file for distribution support
2999    # This is created here before its use later. Its place is hardcoded, so no choice for the path
3000    #
3001    my \$tempconf = pb_distro_conffile();
3002    pb_mkdir_p(dirname(\$tempconf));
3003    open(CONF,"> \$tempconf") || die "Unable to create \$tempconf";
3004    print CONF q{$content};
3005    close(CONF);
3006EOF
3007
[1176]3008    if ($vtype =~ /(v|r)m/) {
[661]3009        print SCRIPT << "EOF";
[354]3010# allow ssh entry to build
3011#
[891]3012mkdir "$home/$pbac->{$ENV{'PBPROJ'}}/.ssh",0700;
[347]3013# Allow those accessing root to access the build account
[891]3014copy("\$ENV{'HOME'}/.ssh/authorized_keys","$home/$pbac->{$ENV{'PBPROJ'}}/.ssh/authorized_keys");
[320]3015chmod 0600,".ssh/authorized_keys";
[891]3016pb_system("chown -R $pbac->{$ENV{'PBPROJ'}}:$pbac->{$ENV{'PBPROJ'}} $home/$pbac->{$ENV{'PBPROJ'}}","Finish setting up the account env for $pbac->{$ENV{'PBPROJ'}}");
[320]3017
[346]3018EOF
[661]3019}
[353]3020    print SCRIPT << 'EOF';
[347]3021# No passwd for build account only keys
[320]3022$file="/etc/shadow";
[684]3023if (-f $file) {
3024    open(PBFILE,$file) || die "Unable to open $file";
3025    open(PBOUT,"> $file.new") || die "Unable to open $file.new";
3026    while (<PBFILE>) {
[346]3027EOF
[353]3028    print SCRIPT << "EOF";
[684]3029        s/^$pbac->{$ENV{'PBPROJ'}}:\!\!:/$pbac->{$ENV{'PBPROJ'}}:*:/;
3030        s/^$pbac->{$ENV{'PBPROJ'}}:\!:/$pbac->{$ENV{'PBPROJ'}}:*:/; #SLES 9 e.g.
[910]3031        s/^$pbac->{$ENV{'PBPROJ'}}:\\*LK\\*:/$pbac->{$ENV{'PBPROJ'}}:NP:/;  #Solaris e.g.
[346]3032EOF
[684]3033        print SCRIPT << 'EOF';
3034        print PBOUT $_;
3035    }
3036    close(PBFILE);
3037    close(PBOUT);
3038    rename("$file.new",$file);
3039    chmod 0640,$file;
3040    }
[320]3041
[448]3042# Keep the VM in text mode
3043$file="/etc/inittab";
[450]3044if (-f $file) {
3045    open(PBFILE,$file) || die "Unable to open $file";
3046    open(PBOUT,"> $file.new") || die "Unable to open $file.new";
3047    while (<PBFILE>) {
3048        s/^(..):5:initdefault:$/$1:3:initdefault:/;
3049        print PBOUT $_;
3050    }
3051    close(PBFILE);
3052    close(PBOUT);
3053    rename("$file.new",$file);
3054    chmod 0640,$file;
[448]3055}
3056
[320]3057# pb has to be added to portage group on gentoo