source: devel/pb/bin/pb @ 1733

Last change on this file since 1733 was 1733, checked in by bruno, 6 years ago
  • the date command should also been added to sudoers (when ntpdate fails or doesn't exist)
  • Property svn:executable set to *
File size: 154.0 KB
Line 
1#!/usr/bin/perl -w
2#
3# Project Builder main application
4#
5# $Id$
6#
7# Copyright B. Cornec 2007-2012
8# Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard
9# Provided under the GPL v2
10
11# Syntax: see at end
12
13use strict 'vars';
14
15# The modules mentioned here are required by pb when used both
16# locally or inside a VE/VM/RM
17# Additional required modules only used locally are called with a require
18# in their respective section
19use Getopt::Long qw(:config auto_abbrev no_ignore_case);
20use Carp qw/confess cluck/;
21use Data::Dumper;
22use English;
23use File::Basename;
24use File::Copy;
25use File::stat;
26use File::Find;
27use Time::localtime qw(localtime);
28use POSIX qw(strftime);
29use lib qw (lib);
30use ProjectBuilder::Version;
31use ProjectBuilder::Base;
32use ProjectBuilder::Display;
33use ProjectBuilder::Conf;
34use ProjectBuilder::Distribution;
35use ProjectBuilder::VCS;
36use ProjectBuilder::CMS;
37use ProjectBuilder::Env;
38use ProjectBuilder::Filter;
39use ProjectBuilder::Changelog;
40use ProjectBuilder::VE;
41
42# Global variables
43$Global::pb_stop_on_error = 0;  # False by default
44$Global::pb_show_sudo = 0;      # False by default
45
46my %opts;                   # CLI Options
47my $action;                 # action to realize
48my $test = "FALSE";         # Not used
49my $pbforce = 0;            # Force VE/VM rebuild
50my $pbsnap = 0;             # Do not use snapshot mode for VM/VE by default
51my $pbkeep = 0;             # keep temporary directory at the end
52my $option = "";            # Not used
53my @pkgs;                   # list of packages
54my $pbtag;                  # Global Tag variable
55my $pbver;                  # Global Version variable
56my $pbscript;               # Name of the script
57my %pbver;                  # per package
58my %pbtag;                  # per package
59my $pbrev;                  # Global REVISION variable
60my $pbaccount;              # Login to use to connect to the VM/RM
61my $pbtarget = undef;       # Target os-ver-arch you want to build for
62my $pbport;                 # Port to use to connect to the VM/RM
63my $newver;                 # New version to create
64my $iso = undef;            # ISO image for the VM to create
65
66my @date = pb_get_date();
67my $pbdate = strftime("%Y-%m-%d", @date);
68
69=pod
70
71=head1 NAME
72
73pb, aka project-builder.org - builds packages for your projects
74
75=head1 DESCRIPTION
76
77pb helps you build various packages directly from your project sources.
78Those sources could be handled by a CMS (Configuration Management System)
79such as Subversion, CVS, Git, Mercurial... or being a simple reference to a compressed tar file.
80It's based on a set of configuration files, a set of provided macros to help
81you keeping build files as generic as possible. For example, a single .spec
82file should be required to generate for all rpm based distributions, even
83if you could also have multiple .spec files if required.
84
85=head1 SYNOPSIS
86
87pb [-vhSq][-r pbroot][-p project][[-s script -a account -P port][-t [os-ver-arch]][-m os-ver-arch[,...]]][-g][-i iso] <action> [<pkg1> ...]
88
89pb [--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> ...]
90
91=head1 OPTIONS
92
93=over 4
94
95=item B<-v|--verbose>
96
97Print a brief help message and exits.
98
99=item B<-q|--quiet>
100
101Do not print any output.
102
103=item B<-h|--help>
104
105Print a brief help message and exits.
106
107=item B<-S|--snapshot>
108
109Use the snapshot mode of VMs or VEs
110
111=item B<--man>
112
113Prints the manual page and exits.
114
115=item B<-t|--target os-ver-arch>
116
117Name of the target system you want to build for.
118All if none precised.
119
120=item B<-m|--machine os-ver-arch[,os-ver-arch,...]>
121
122Name of the Virtual Machines (VM), Virtual Environments (VE) or Remote Machines (RM)
123you want to build on (comma separated).
124All if none precised (or use the env variable PBV).
125
126=item B<-s|--script script>
127
128Name of the script you want to execute on the related VMs/VEs/RMs.
129
130=item B<-g|--nographic>
131
132Do not launch VMs in graphical mode.
133
134=item B<-i|--iso iso_image>
135
136Name of the ISO image of the distribution you want to install on the related VMs.
137
138=item B<-a|--account account>
139
140Name of the account to use to connect on the related VMs/RMs.
141
142=item B<-P|--port port_number>
143
144Port number to use to connect on the related VMs/RMs.";
145
146=item B<-p|--project project_name>
147
148Name of the project you're working on (or use the env variable PBPROJ)
149
150=item B<-r|--revision revision>
151
152Path Name of the project revision under the CMS (or use the env variable PBROOT)
153
154=item B<-V|--version new_version>
155
156New version of the project to create based on the current one.
157
158=item B<-k|--keep>
159
160Keep the temporary dir where files have been created in or der to help debug
161
162=item B<--rebuild>
163
164Only valid with the checkssh action, it alllows to automatically relaunch the build of the failed packages
165
166=item B<--no-stop-on-error>
167
168Continue through errors with best effort.
169
170=back
171
172=head1 ARGUMENTS
173
174<action> can be:
175
176=over 4
177
178=item B<sbx2build>
179
180Create tar files for the project under your CMS.
181Current state of the exported content is taken.
182CMS supported are SVN, SVK, CVS, Git and Mercurial
183parameters are packages to build
184if not using default list
185
186=item B<cms2build>
187
188Create tar files for the project under your CMS.
189Current state of the CMS is taken.
190CMS supported are SVN, SVK, CVS, Git and Mercurial
191parameters are packages to build
192if not using default list
193
194=item B<build2pkg>
195
196Create packages for your running distribution
197
198=item B<cms2pkg>
199
200cms2build + build2pkg
201
202=item B<sbx2pkg>
203
204sbx2build + build2pkg
205
206=item B<sbx2pkg2ins>
207
208sbx2pkg + final install of packages
209
210=item B<build2ssh>
211
212Send the tar files to a SSH host
213
214=item B<sbx2ssh>
215
216sbx2build + build2ssh
217
218=item B<cms2ssh>
219
220cms2build + build2ssh
221
222=item B<pkg2ssh>
223
224Send the packages built to a SSH host
225
226=item B<build2vm>
227
228Create packages in VMs, launching them if needed
229and send those packages to a SSH host once built
230VM type supported are QEMU and KVM
231
232=item B<build2ve>
233
234Create packages in VEs, creating it if needed
235and send those packages to a SSH host once built
236
237=item B<build2rm>
238
239Create packages in RMs, which should pre-exist,
240and send those packages to a SSH host once built
241RM means Remote Machine, and could be a physical or Virtual one.
242This is one buildfarm integration for pb.
243
244=item B<sbx2vm>
245
246sbx2build + build2vm
247
248=item B<sbx2ve>
249
250sbx2build + build2ve
251
252=item B<sbx2rm>
253
254sbx2build + build2rm
255
256=item B<cms2vm>
257
258cms2build + build2vm
259
260=item B<cms2ve>
261
262cms2build + build2ve
263
264=item B<cms2rm>
265
266cms2build + build2rm
267
268=item B<launchvm>
269
270Launch one virtual machine
271
272=item B<launchve>
273
274Launch one virtual environment
275
276=item B<script2vm>
277
278Launch one virtual machine if needed
279and executes a script on it
280
281=item B<script2ve>
282
283Execute a script in a virtual environment
284
285=item B<script2rm>
286
287Execute a script on a remote machine
288
289=item B<newvm>
290
291Create a new virtual machine
292
293=item B<newve>
294
295Create a new virtual environment
296
297=item B<setupvm>
298
299Setup a virtual machine for pb usage
300
301=item B<setupve>
302
303Setup a virtual environment for pb usage
304
305=item B<setuprm>
306
307Setup a remote machine for pb usage
308
309=item B<sbx2setupvm>
310
311Setup a virtual machine for pb usage using the sandbox version of pb instead of the latest stable
312Reserved to dev team.
313
314=item B<sbx2setupve>
315
316Setup a virtual environment for pb usage using the sandbox version of pb instead of the latest stable
317Reserved to dev team.
318
319=item B<sbx2setuprm>
320
321Setup a remote machine for pb usage using the sandbox version of pb instead of the latest stable
322Reserved to dev team.
323
324=item B<build2setupvm>
325
326Setup a virtual machine for pb usage using the build available
327Reserved to dev team.
328
329=item B<build2setupve>
330
331Setup a virtual environment for pb usage using the build available
332Reserved to dev team.
333
334=item B<build2setuprm>
335
336Setup a remote machine for pb usage using the build available
337Reserved to dev team.
338
339=item B<snapvm>
340
341Snapshot a virtual machine for pb usage
342
343=item B<snapve>
344
345Snapshot a virtual environment for pb usage
346
347=item B<updatevm>
348
349Update the distribution in the virtual machine
350
351=item B<updateve>
352
353Update the distribution in the virtual environment
354
355=item B<updaterm>
356
357Update the distribution in the remote machine
358
359=item B<test2pkg>
360
361Test a package locally
362
363=item B<test2vm>
364
365Test a package in a virtual machine
366
367=item B<test2ve>
368
369Test a package in a virtual environment
370
371=item B<test2rm>
372
373Test a package in a remote machine
374
375=item B<checkssh>
376
377Check the delivery of the packages on the repository
378
379=item B<newver>
380
381Create a new version of the project derived
382from the current one
383
384=item B<newproj>
385
386Create a new project and a template set of
387configuration files under pbconf
388
389=item B<announce>
390
391Announce the availability of the project through various means
392
393=item B<sbx2webssh>
394
395Create tar files for the website under your CMS.
396Current state of the exported content is taken.
397Deliver the content to the target server using ssh from the exported dir.
398
399=item B<cms2webssh>
400
401Create tar files for the website from your CMS.
402Deliver the content to the target server using ssh from the DVCS.
403
404=item B<sbx2webpkg>
405
406Create tar files for the website under your CMS.
407Current state of the exported content is taken.
408
409=item B<cms2webpkg>
410
411Create tar files for the website under your CMS.
412
413=item B<getconf>
414
415Print the full configuration parameters as found in the various configuration files. help to debug conf issues.
416
417=item B<clean>
418
419Purge the build and delivery directories related to the current project
420
421=item B<cleanssh>
422
423Purge the ssh server of its packages (only for testver and test packages)
424
425=back
426
427<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).
428
429=head1 WEB SITES
430
431The 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/>.
432
433=head1 USER MAILING LIST
434
435None exists for the moment.
436
437=head1 CONFIGURATION FILES
438
439Each pb user may have a configuration in F<$HOME/.pbrc>. The values in this file may overwrite any other configuration file value.
440
441Here is an example of such a configuration file:
442
443 #
444 # Define for each project the URL of its pbconf repository
445 # No default option allowed here as they need to be all different
446 #
447 # URL of the pbconf content
448 # This is the format of a classical URL with the extension of additional schema such as
449 # svn+ssh, cvs+ssh, ...
450 #
451 pbconfurl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe/pbconf
452
453 # This is normaly defined in the project's configuration file
454 # Url of the project
455 #
456 pburl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe
457 
458 # All these URLs needs to be defined here as the are the entry point
459 # for how to build packages for the project
460 #
461 pbconfurl pb = svn+ssh://svn.project-builder.org/mondo/svn/pb/pbconf
462 pbconfurl mondorescue = svn+ssh://svn.project-builder.org/mondo/svn/project-builder/mondorescue/pbconf
463 pbconfurl collectl = svn+ssh://bruno@svn.mondorescue.org/mondo/svn/project-builder/collectl/pbconf
464 pbconfurl netperf = svn+ssh://svn.mondorescue.org/mondo/svn/project-builder/netperf/pbconf
465 
466 # Under that dir will take place everything related to pb
467 # If you want to use VMs/chroot/..., then use $ENV{'HOME'} to make it portable
468 # to your VMs/chroot/...
469 # if not defined then /var/cache
470 pbdefdir default = $ENV{'HOME'}/project-builder
471 pbdefdir pb = $ENV{'HOME'}
472 pbdefdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
473 pbdefdir mondorescue = $ENV{'HOME'}/mondo/svn
474 
475 # pbconfdir points to the directory where the CMS content of the pbconfurl is checked out
476 # If not defined, pbconfdir is under pbdefdir/pbproj/pbconf
477 pbconfdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs/pbconf
478 pbconfdir mondorescue = $ENV{'HOME'}/mondo/svn/pbconf
479 
480 # pbdir points to the directory where the CMS content of the pburl is checked out
481 # If not defined, pbdir is under pbdefdir/pbproj
482 # Only defined if we have access to the dev of the project
483 pbdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs
484 pbdir mondorescue = $ENV{'HOME'}/mondo/svn
485 
486 # -daemonize doesn't work with qemu 0.8.2
487 vmopt default = -m 384
488
489=head1 COMMAND DETAILS
490
491=head2 newproj
492
493The newproj command creates a new project-builder project.  To run this command you first need to define two variables in your ~/.pbrc file:
494
495 pbconfurl I<project> = file:///home/anderse/.git/project-builder-config/I<project>
496 pbdefdir default = $ENV{HOME}/cache-project-builder
497
498The first line defines the version controlled configuration information and the second defines the root directory for project-builder to use.
499
500You can then run the command:
501
502 % pb -p I<$project> -r I<$version> newproj I<$pkg>
503
504to create the new project. Running the newproj command will then generate the file $pbdefdir/$project/pbconf/$version/$project.pb, and the directory $pbdefdir/$project/pbconf/$version/$pkg. You will need to edit those files to make the later commands work.
505
506=head2 cms2build
507
508The cms2build command takes your files from the content management system and makes the two tar files that are necessary for building files. You need to have run the newproj command first.  Then there are several steps for running this command:
509
510=over 4
511
512=item Update your $project.pb configuration file.
513
514You need to set the pburl, pbrepo, pbwf, pbpackager, projver, projtag, testver, delivery, and defpkgdir lines as described in the configuration file. The pburl entry is used to find the source for your package. The pbrepo entry is used to build the .repo or .sources.list files for use by downloaders of the package. The pbwf entry indicates that the source tar file is named by I<package-name>-I<version>. The pbpackager entry will be stored in the packages and should be you or your team. The projver/projtag entries indicate the version of the software and the version of the packaging scripts. The testver entry when true indicates that the package is in a test version, so no log file is computed (can be long), and version is made up using a timstamp. The delivery entry gives the subdirectory under which the packages will be delivered on the repository, and the defpkgdir entry corresponds to the local subdirectory hosting the package content.
515
516For example:
517
518 pburl Lintel = file:///home/anderse/projects/Lintel-0.2012.02.28.tar.gz
519 pbrepo Lintel = http://tesla.hpl.hp.com/opensource
520 pbwf Lintel = 1
521 pbpackager Lintel = Eric Anderson <eric.anderson4@hp.com>
522 projver Lintel = 0.2012.02.28
523 projtag Lintel = 1
524 testver Lintel = false
525 delivery Lintel = production
526 defpkgdir Lintel = Lintel-0.2012.02.28
527
528=item Create the build .tar.gz files:
529
530Then you need to take those files and create the initial tar files.  Run a command like:
531
532 % pb -p $project -r $version cms2build
533
534To create the $pbdefdir/$project/delivery/$project-$version.{,pbconf}.tar.gz files, the $version-$projtag.pb and pbrc files in the same directory.
535
536=back
537
538=head2 build2pkg
539
540The build2pkg command takes the tar files created in the cms2build step and attempts to build binary packages for your current operating system. There are two steps:
541
542=over 4
543
544=item Update your filters and build files.
545
546You probably need to edit the files describing the build steps in one of the $pbdefdir/$project/pbconf/$version/$project/{deb,rpm,pkg} directories and the filters in $pbdefdir/$project/pbconf/$version/pbfilter. Note that you can define additional filters and transforms in the *.pbf files. The build files will be filtered by the filters defined in the *.pbf files to generate the inputs to the build step. Therefore, if you change those files, you need to re-run the cms2build step.
547
548=item Build the package.
549
550Then you can run a command like:
551
552 % pb -p $project -r $version build2pkg
553
554To create the files in $project/build that comprise your binary package(s).
555
556=back
557
558=head2 newve
559 
560The 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:
561
562=over 4
563
564=item Update ~/.pbrc
565
566Update your ~/.pbrc file to specify the vepath, velist, velogin, and vetype variables, e.g.:
567
568 vepath default = $ENV{HOME}/cache-project-builder/chroot
569 velist default = debian-6.0-i386
570 velogin default = pb
571 vetype default = chroot
572
573If you are building for rpm style OS's, update the verpmtype option, and install the appropriate tool.
574
575 verpmtype default = rpmbootstrap
576
577You 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:
578
579 rbsmirrorsrv debian = http://mirrors1.kernel.org/debian/
580 http_proxy default = http://localhost:3128/
581 ftp_proxy default = http://localhost:3128/
582
583=item Run the cms2build command
584
585If 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.
586
587=item Create the new virtual environment
588
589Initialize the new operating system. This step will install the core OS packages for the virtual environment, e.g.:
590
591 % pb -v -p $project -m debian-6.0-i386 newve
592
593=back
594
595=head2 setupve
596
597The setupve command prepares a virtual environment for use by project builder. In particular it installs project-builder from the packages into the virtual environment. Two sub-steps are necessary:
598
599=over 4
600
601=item Update $project.pb
602
603You need to have a sshhost entry for setupve to work, so add one, even an invalid one, e.g.:
604
605 sshhost $project = foo.example.org
606
607=item Setup the virtual environment
608
609 % pb -v -p $project -m debian-6.0-i386 setupve
610
611If you prefer to install the current SVN version of project builder, you can substitute the setupve option by the sbx2setupv one.
612
613=back
614
615=head2 build2ve
616
617The build2ve command is similar to the build2pkg command in that it will take the sources created by cms2build and turn them into binary packages. The command has two differences. First, it creates the packages in a virtual environment, i.e. the one made by an earlier setupve setup. Second it copies the resulting packages to a repository and builds the repository meta-data needed.
618
619Three sub-steps are needed:
620
621=over 4
622
623=item Update $project.pb
624
625You need to have a valid sshdir and sshhost entry for build2ve to work, so add them. Note that you need to be able to ssh from the host you run the command on to the repository host, preferably without needing to type in a password, so using ssh-agent or having a special passwordless project-builder ssh key will make this step easier.
626
627 sshhost $project = localhost
628 sshdir $project = $home/cache-project-builder/repos
629
630You may also need to specify additional repository files to use or rpms to install. Note the URL for repositories is not the URL of the repository, but the URL of a file that can be put in the yum.repos.d or apt.sources.d directory.
631
632 addrepo centos-5-i386 = http://localhost/pb/centos-extras.repo,http://mirror.centos.org/centos/5/extras/i386/RPMS/chrpath-0.13-3.el5.centos.i386.rpm
633
634=item Update your filters and build files
635
636You may need to update your filter files (*.pbf) as in the build2pkg step if you are building for a new OS or architecture.
637
638=item Build the packages and copy them to the repository
639
640 % pb -v -p $project -m debian-6.0-i386 build2ve
641
642=back
643
644*Debugging:* If the build fails (and you did not specify the --no-stop-on-error) option, then the virtual environment and scripts should still be present and configured to build the package. You can run a command like 'sudo setarch i386 chroot $path bash' in order to get into the environment. In your log you should see a command like that. From there you can go into the /home/pb directory as the pb user and run the same style of pb commands as you did when doing build2pkg. This will help you figure out what has gone wrong in the build in the virtual environment.
645
646=head1 AUTHORS
647
648The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
649
650=head1 COPYRIGHT
651
652Project-Builder.org is distributed under the GPL v2.0 license
653described in the file C<COPYING> included with the distribution.
654
655=cut
656
657# ---------------------------------------------------------------------------
658
659my ($projectbuilderver,$projectbuilderrev) = pb_version_init();
660my $appname = "pb";
661
662# Initialize the syntax string
663
664pb_syntax_init("$appname (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n");
665
666GetOptions("help|?|h+" => \$opts{'h'}, 
667        "man" => \$opts{'man'},
668        "verbose|v+" => \$opts{'v'},
669        "snapshot|S" => \$opts{'S'},
670        "quiet|q" => \$opts{'q'},
671        "log-files|l=s" => \$opts{'l'},
672        "force|f" => \$opts{'f'},
673        "account|a=s" => \$opts{'a'},
674        "revision|r=s" => \$opts{'r'},
675        "script|s=s" => \$opts{'s'},
676        "machines|mock|m=s" => \$opts{'m'},
677        "target|t:s" => \$opts{'t'},
678        "nographic|g" => \$opts{'g'},
679        "port|P=i" => \$opts{'P'},
680        "project|p=s" => \$opts{'p'},
681        "rebuild" => \$opts{'rebuild'},
682        "iso|i=s" => \$opts{'i'},
683        "version|V=s" => \$opts{'V'},
684        "keep|k" => \$opts{'k'},
685        "stop-on-error!" => \$Global::pb_stop_on_error,
686) || pb_syntax(-1,0);
687
688if (defined $opts{'l'}) {
689    open(pbLOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!";
690    $pbLOG = \*pbLOG;
691    $pbdebug = 0  if ($pbdebug == -1);
692    }
693pb_log_init($pbdebug, $pbLOG);
694
695if (defined $opts{'h'}) {
696    pb_syntax(0,$opts{'h'}-1);
697}
698if (defined $opts{'man'}) {
699    pb_syntax(0,2);
700}
701if (defined $opts{'v'}) {
702    $pbdebug = $opts{'v'};
703}
704if (defined $opts{'f'}) {
705    $pbforce=1;
706}
707if (defined $opts{'q'}) {
708    $pbdebug=-1;
709}
710if (defined $opts{'S'}) {
711    $pbsnap=1;
712}
713if (defined $opts{'k'}) {
714    $pbkeep=1;
715}
716pb_display_init("text","");
717
718# Handle root of the project if defined
719if (defined $opts{'r'}) {
720    $ENV{'PBROOTDIR'} = $opts{'r'};
721}
722# Handle virtual machines if any
723if (defined $opts{'m'}) {
724    $ENV{'PBV'} = $opts{'m'};
725}
726if (defined $opts{'s'}) {
727    $pbscript = $opts{'s'};
728}
729if (defined $opts{'a'}) {
730    $pbaccount = $opts{'a'};
731    die "option -a requires a -s script option" if (not defined $pbscript);
732}
733if (defined $opts{'P'}) {
734    $pbport = $opts{'P'};
735}
736if (defined $opts{'V'}) {
737    $newver = $opts{'V'};
738}
739if (defined $opts{'i'}) {
740    $iso = $opts{'i'};
741}
742if (defined $opts{'t'}) {
743    $pbtarget = $opts{'t'};
744}
745
746# Get Action
747$action = shift @ARGV;
748die pb_syntax(-1,1) if (not defined $action);
749
750my ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir);
751my $pbinit = undef;
752$pbinit = 1 if ($action =~ /^newproj$/);
753
754# Handles project name if any
755# And get global params
756($filteredfiles, $supfiles, $defpkgdir, $extpkgdir) = pb_env_init($opts{'p'},$pbinit,$action,$pbkeep);
757
758#
759# Check for command requirements
760#
761my ($req,$opt,$pbpara,$pbshowsudo,$pbstoponerr) = pb_conf_get_if("oscmd","oscmdopt","pbparallel","pbshowsudo","pbstoponerr");
762pb_check_requirements($req,$opt,$appname);
763
764$Global::pb_show_sudo = 1 if ((defined $pbshowsudo) && (defined $pbshowsudo->{$ENV{'PBPROJ'}}) && ($pbshowsudo->{$ENV{'PBPROJ'}} =~ /true/oi));
765$Global::pb_stop_on_error = 1 if ((defined $pbstoponerr) && (defined $pbstoponerr->{$ENV{'PBPROJ'}}) && ($pbstoponerr->{$ENV{'PBPROJ'}} =~ /true/oi));
766
767#
768# Check if we can launch some actions in // with Parallel::ForkManager
769#
770my $pbparallel = $pbpara->{$appname} if (defined $pbpara);
771if (not defined $pbparallel) {
772    eval
773    {
774        require Sys::CPU;
775        Sys::CPU->import();
776    };
777    if ($@) {
778        # Sys::CPU not found, defaulting to 1
779        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");
780        $pbparallel = 1;
781    } else {
782        # Using the number of cores
783        $pbparallel = Sys::CPU::cpu_count();
784        pb_log(1,"Using parallel mode with $pbparallel processes\n");
785    }
786}
787
788eval
789{
790    require Parallel::ForkManager;
791    Parallel::ForkManager->import();
792};
793# Parallel::ForkManager not found so no // actions
794if ($@) {
795    $pbparallel = undef;
796    pb_log(1,"ADVISE: Install Parallel::ForkManager to benefit from automatic parallelism optimization.\nOnly 1 process at a time for the moment\n");
797}
798
799pb_log(0,"Project: $ENV{'PBPROJ'}\n");
800pb_log(0,"Action: $action\n");
801
802my $do_install = undef;
803# Possibility to add a 2ins to some commands to launch automatic installation
804$do_install = 1 if ($action =~ /2ins$/);
805
806# Act depending on action
807if ($action =~ /^cms2build$/) {
808    pb_cms2build("CMS");
809} elsif ($action =~ /^sbx2build$/) {
810    pb_cms2build("SandBox");
811} elsif ($action =~ /^build2pkg/) {
812    pb_build2pkg($do_install);
813} elsif ($action =~ /^cms2pkg/) {
814    pb_cms2build("CMS");
815    pb_build2pkg($do_install);
816} elsif ($action =~ /^sbx2pkg/) {
817    pb_cms2build("SandBox");
818    pb_build2pkg($do_install);
819} elsif ($action =~ /^build2ssh$/) {
820    pb_build2ssh();
821} elsif ($action =~ /^cms2ssh$/) {
822    pb_cms2build("CMS");
823    pb_build2ssh();
824} elsif ($action =~ /^sbx2ssh$/) {
825    pb_cms2build("SandBox");
826    pb_build2ssh();
827} elsif ($action =~ /^pkg2ssh$/) {
828    pb_pkg2ssh();
829} elsif ($action =~ /^build2rm$/) {
830    pb_build2v("rm","build");
831} elsif ($action =~ /^build2ve$/) {
832    pb_build2v("ve","build");
833} elsif ($action =~ /^build2vm$/) {
834    pb_build2v("vm","build");
835} elsif ($action =~ /^cms2rm$/) {
836    pb_cms2build("CMS");
837    pb_build2v("rm","build");
838} elsif ($action =~ /^cms2ve$/) {
839    pb_cms2build("CMS");
840    pb_build2v("ve","build");
841} elsif ($action =~ /^sbx2rm$/) {
842    pb_cms2build("SandBox");
843    pb_build2v("rm","build");
844} elsif ($action =~ /^sbx2ve$/) {
845    pb_cms2build("SandBox");
846    pb_build2v("ve","build");
847} elsif ($action =~ /^cms2vm$/) {
848    pb_cms2build("CMS");
849    pb_build2v("vm","build");
850} elsif ($action =~ /^sbx2vm$/) {
851    pb_cms2build("SandBox");
852    pb_build2v("vm","build");
853} elsif ($action =~ /^launchvm$/) {
854    my $pm;
855    my $all_ok = 1;
856    if (defined $pbparallel) {
857        $pm = new Parallel::ForkManager($pbparallel);
858   
859        # Set which port the VM/RM will use to communicate
860        $pm->run_on_start(\&pb_set_port);
861        $pm->run_on_finish(sub { my ($pid, $code, $id, $signal, $dump) = @_;
862                            $all_ok = 0 unless (($code == 0) && ($signal == 0) && ($dump == 0)); 
863                        });
864    }
865
866    my $counter = 0;
867    foreach my $v (split(/,/,$ENV{'PBV'})) {
868        $counter++;
869        # Modulo pbparallel
870        $counter = 1 if ((defined $pbparallel) && ($counter > $pbparallel));
871        $pm->start($counter) and next if (defined $pbparallel);
872
873        pb_launchv("vm",$v,0);
874    }
875    $pm->wait_all_children if (defined $pbparallel);
876    die "Aborting, one or more of the children failed." if ((not $all_ok) && ($Global::pb_stop_on_error));
877} elsif ($action =~ /^launchve$/) {
878    pb_launchv("ve",$ENV{'PBV'},0);
879} elsif ($action =~ /^script2vm$/) {
880    pb_script2v($pbscript,"vm");
881} elsif ($action =~ /^script2ve$/) {
882    pb_script2v($pbscript,"ve");
883} elsif ($action =~ /^script2rm$/) {
884    pb_script2v($pbscript,"rm");
885} elsif ($action =~ /^newver$/) {
886    pb_newver();
887} elsif ($action =~ /^newve$/) {
888    pb_launchv("ve",$ENV{'PBV'},1);
889} elsif ($action =~ /^newvm$/) {
890    pb_launchv("vm",$ENV{'PBV'},1);
891    pb_log(0, "Please ensure that sshd is running in your VM by default\n");
892    pb_log(0, "and that it allows remote root login (PermitRootLogin yes in /etc/ssh/sshd_config)\n");
893    pb_log(0, "Also ensure that network is up, firewalling correctly configured\n");
894    pb_log(0, "and perl, tar, sudo, ntpdate and scp/ssh installed\n");
895    pb_log(0, "You should then be able to login with ssh -p VMPORT root\@localhost (if VM started with pb)\n");
896} elsif ($action =~ /^setuprm$/) {
897    pb_setup2v("rm");
898} elsif ($action =~ /^setupve$/) {
899    pb_setup2v("ve");
900} elsif ($action =~ /^setupvm$/) {
901    pb_setup2v("vm");
902} elsif ($action =~ /^sbx2setuprm$/) {
903    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
904    pb_cms2build("SandBox");
905    pb_setup2v("rm","SandBox");
906} elsif ($action =~ /^sbx2setupve$/) {
907    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
908    pb_cms2build("SandBox");
909    pb_setup2v("ve","SandBox");
910} elsif ($action =~ /^sbx2setupvm$/) {
911    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
912    pb_cms2build("SandBox");
913    pb_setup2v("vm","SandBox");
914} elsif ($action =~ /^build2setuprm$/) {
915    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
916    pb_setup2v("rm","SandBox");
917} elsif ($action =~ /^build2setupve$/) {
918    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
919    pb_setup2v("ve","SandBox");
920} elsif ($action =~ /^build2setupvm$/) {
921    die "This feature is limited to the pb project" if ($ENV{'PBPROJ'} ne $appname);
922    pb_setup2v("vm","SandBox");
923} elsif ($action =~ /^updaterm$/) {
924    pb_update2v("rm");
925} elsif ($action =~ /^updateve$/) {
926    pb_update2v("ve");
927} elsif ($action =~ /^updatevm$/) {
928    pb_update2v("vm");
929} elsif ($action =~ /^snapve$/) {
930    pb_snap2v("ve");
931} elsif ($action =~ /^snapvm$/) {
932    pb_snap2v("vm");
933} elsif ($action =~ /^test2pkg$/) {
934    pb_test2pkg();
935} elsif ($action =~ /^test2rm$/) {
936    pb_build2v("rm","test");
937} elsif ($action =~ /^test2ve$/) {
938    pb_build2v("ve","test");
939} elsif ($action =~ /^test2vm$/) {
940    pb_build2v("vm","test");
941} elsif ($action =~ /^newproj$/) {
942    # Nothing to do - already done in pb_env_init
943} elsif ($action =~ /^getconf$/) {
944    my $pbos = pb_distro_get_context();
945    pb_conf_print();
946} elsif ($action =~ /^clean$/) {
947    pb_clean();
948} elsif ($action =~ /^announce$/) {
949    # For announce only. Require avoids the systematic load of these modules
950    require DBI;
951    require DBD::SQLite;
952
953    pb_announce("Announce");
954} elsif ($action =~ /^cleanssh$/) {
955    pb_announce("Clean");
956} elsif ($action =~ /^checkssh$/) {
957    pb_announce("Check");
958} elsif ($action =~ /^sbx2webpkg$/) {
959    require DBI;
960    require DBD::SQLite;
961
962    pb_cms2build("SandBox","Web");
963} elsif ($action =~ /^sbx2webssh$/) {
964    require DBI;
965    require DBD::SQLite;
966
967    pb_cms2build("SandBox","Web");
968    pb_send2target("Web");
969} elsif ($action =~ /^cms2webpkg$/) {
970    require DBI;
971    require DBD::SQLite;
972
973    pb_cms2build("CMS","Web");
974} elsif ($action =~ /^cms2webssh$/) {
975    require DBI;
976    require DBD::SQLite;
977
978    pb_cms2build("CMS","Web");
979    pb_send2target("Web");
980} else {
981    pb_log(0,"\'$action\' is not available\n");
982    pb_syntax(-2,1);
983}
984
985pb_exit();
986
987sub pb_cms2build {
988
989    my $param = shift || undef;
990    my $web = shift || undef;
991
992    my $pkg;
993    my @pkgs;
994    my $webdir;
995
996    my %pkgs;
997    my $pb;             # Structure to store conf info
998
999    die "pb_cms2build requires a parameter: SandBox or CMS" if (not defined $param);
1000
1001    # If Website, then pkg is only the website
1002    if (defined $web) {
1003        ($webdir) = pb_conf_get("webdir");
1004        pb_log(2,"webdir: ".Dumper($webdir)."\n");
1005        $pkgs[0] = $webdir->{$ENV{'PBPROJ'}};
1006        $extpkgdir = $webdir;
1007        pb_log(0,"Package: $pkgs[0]\n");
1008    } else {
1009        $pkg = pb_cms_get_pkg($defpkgdir,$extpkgdir);
1010        @pkgs = @$pkg;
1011    }
1012
1013    my ($scheme, $uri) = pb_cms_init($pbinit,$param);
1014
1015    # We need 2 lines here
1016    my ($pkgv, $pkgt, $testver) = pb_conf_get_if("pkgver","pkgtag","testver");
1017
1018    # declare packager and repo for filtering
1019    my ($tmp1, $tmp2) = pb_conf_get("pbpackager","pbrepo");
1020    $ENV{'PBPACKAGER'} = $tmp1->{$ENV{'PBPROJ'}};
1021    $ENV{'PBREPO'} = $tmp2->{$ENV{'PBPROJ'}};
1022    my ($delivery) = pb_conf_get_if("delivery");
1023    $delivery->{$ENV{'PBPROJ'}} = "" if (not defined $delivery->{$ENV{'PBPROJ'}});
1024
1025    # If we deal with a test dir, we want to keep the date in tar file and dir name
1026    my $pbextdir = "";
1027        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
1028            $pbextdir = strftime("%Y%m%d%H%M%S", @date);
1029    }
1030
1031    foreach my $pbpkg (@pkgs) {
1032        $ENV{'PBPKG'} = $pbpkg;
1033
1034        if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) {
1035            $pbver = $pkgv->{$pbpkg};
1036        } else {
1037            $pbver = $ENV{'PBPROJVER'};
1038        }
1039        # If it's a test version, then tag == 0
1040        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
1041            $pbtag = "0";
1042            $ENV{'PBPROJTAG'} = $pbtag;
1043        } elsif ((defined $pkgt) && (defined $pkgt->{$pbpkg})) {
1044            $pbtag = $pkgt->{$pbpkg};
1045        } else {
1046            $pbtag = $ENV{'PBPROJTAG'};
1047        }
1048
1049        $pbrev = $ENV{'PBREVISION'};
1050        pb_log(0,"\n");
1051        pb_log(0,"Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n");
1052        die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
1053
1054        my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir";
1055        # Create the structure if needed
1056        pb_mkdir_p($dest);
1057        # Clean up dest if necessary. The export will recreate it
1058        pb_rm_rf($dest) if (-d $dest);
1059
1060        # Export CMS tree for the concerned package to dest
1061        # And generate some additional files
1062        $OUTPUT_AUTOFLUSH=1;
1063
1064        # computes in which dir we have to work
1065        my $dir = $defpkgdir->{$pbpkg};
1066        $dir = $extpkgdir->{$pbpkg} if (not defined $dir);
1067        $dir = $webdir->{$ENV{'PBPROJ'}} if (defined $web);
1068        die "Variable \$dir not defined. Please report to dev team with log of a verbose run and this info ".Dumper($defpkgdir,$extpkgdir,$webdir) if (not defined $dir);
1069        pb_log(2,"def:".Dumper($defpkgdir)."ext: ".Dumper($extpkgdir)."dir: $dir\n");
1070
1071        # Exporting content from CMS
1072        my $sourcedir = undef;
1073        my $sourceuri = $uri;
1074        if ($param eq "SandBox") {
1075            # Point to the local instance
1076            $sourcedir = "$ENV{'PBDIR'}/$dir";
1077        } else {
1078            # Get it from a subdir of the URI with same version as localy but different root
1079            # Only if using a real CMS
1080            my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
1081            if (($scheme !~ /^file/) && ($scheme !~ /^(ht|f)tp/)) {
1082                $sourceuri = "$ENV{'PBDIR'}/$dir"; 
1083                $sourceuri =~ s|^$ENV{'PBPROJDIR'}/|$uri/|;
1084            }
1085        }
1086        my $preserve = pb_vcs_export($sourceuri,$sourcedir,$dest);
1087
1088        # Generated fake content for test versions to speed up stuff
1089        my $chglog;
1090
1091        # Get project info on authors and log file
1092        # TODO: Make it CMS aware
1093        $chglog = "$ENV{'PBROOTDIR'}/$pbpkg/pbcl";
1094        $chglog = "$ENV{'PBROOTDIR'}/pbcl" if (! -f $chglog);
1095        $chglog = undef if (! -f $chglog);
1096
1097        # TODO: Make it CMS aware
1098        my $authors = "$ENV{'PBROOTDIR'}/$pbpkg/pbauthors";
1099        $authors = "$ENV{'PBROOTDIR'}/pbauthors" if (! -f $authors);
1100        $authors = "/dev/null" if (! -f $authors);
1101
1102        # Extract cms log history and store it
1103        if ((defined $chglog) && (! -f "$dest/NEWS")) {
1104            pb_log(2,"Generating NEWS file from $chglog\n");
1105            copy($chglog,"$dest/NEWS") || die "Unable to create $dest/NEWS";
1106        }
1107        pb_cms_log($scheme,"$ENV{'PBDIR'}/$dir",$dest,$chglog,$authors,$testver);
1108
1109        my %build;
1110        # We want to at least build for the underlying distro
1111        # except if a target was given, in which case we only build for it
1112        # if -t was passed without target then build for the native distro.
1113        my $pbos = pb_distro_get_context($pbtarget);
1114        my $tmpl = pb_get_distros($pbos,$pbtarget);
1115
1116        # Setup $pb structure to allow filtering later on, on files using that structure
1117        $pb->{'tag'} = $pbtag;
1118        $pb->{'rev'} = $pbrev;
1119        $pb->{'ver'} = $pbver;
1120        $pb->{'pkg'} = $pbpkg;
1121        $pb->{'suf'} = $pbos->{'suffix'};
1122        $pb->{'realpkg'} = $pbpkg;
1123        $pb->{'date'} = $pbdate;
1124        $pb->{'defpkgdir'} = $defpkgdir;
1125        $pb->{'extpkgdir'} = $extpkgdir;
1126        $pb->{'chglog'} = $chglog;
1127        $pb->{'extdir'} = $pbextdir;
1128        $pb->{'packager'} = $ENV{'PBPACKAGER'};
1129        $pb->{'proj'} = $ENV{'PBPROJ'};
1130        $pb->{'repo'} = "$ENV{'PBREPO'}/$delivery->{$ENV{'PBPROJ'}}";
1131        $pb->{'patches'} = ();
1132        $pb->{'sources'} = ();
1133   
1134        my $tmpd = "$ENV{'PBTMP'}/cms.$$";
1135        pb_mkdir_p($tmpd) if (defined $pbparallel);
1136
1137        # Get only all.pbf filter at this stage for pbinit
1138        my $ptr = pb_get_filters($pbpkg);
1139
1140        # Do not do that for website
1141        if (not defined $web) {
1142            my %virt;
1143            # De-duplicate similar VM/VE/RM
1144            foreach my $d (split(/,/,$tmpl)) {
1145                # skip ill-formatted vms (name-ver-arch)
1146                next if ($d !~ /-/);
1147                $virt{$d} = $d;
1148            }
1149
1150            # Try to use // processing here
1151            my $all_ok = 1;
1152            my $pm = new Parallel::ForkManager($pbparallel) if (defined $pbparallel);
1153            $pm->run_on_finish(sub { my ($pid, $code, $id, $signal, $dump) = @_;
1154                                    $all_ok = 0 unless (($code == 0) && ($signal == 0) && ($dump == 0)); }) if (defined $pbparallel);
1155
1156            pb_log(0,"Preparing delivery ...\n");
1157            foreach my $v (keys %virt) {
1158                $pm->start and next if (defined $pbparallel);
1159
1160                # Distro context
1161                my $pbos = pb_distro_get_context($v);
1162   
1163                $pb->{'pbos'} = $pbos;
1164                $pb->{'suf'} = $pbos->{'suffix'};
1165                pb_log(3,"DEBUG: pb: ".Dumper($pb)."\n");
1166
1167                # Get all filters to apply
1168                $ptr = pb_get_filters($pbpkg,$pbos);
1169   
1170                pb_log(2,"DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n");
1171   
1172                # We need to compute the real name of the package
1173                my $pbrealpkg = pb_cms_get_real_pkg($pbpkg,$pbos->{'type'});
1174                $pb->{'realpkg'} = $pbrealpkg;
1175                pb_log(1,"Virtual package $pbpkg has a real package name of $pbrealpkg on $pbos->{'name'}-$pbos->{'version'}\n") if ($pbrealpkg ne $pbpkg);
1176   
1177                # Filter build files from the less precise up to the most with overloading
1178                # Filter all files found, keeping the name, and generating in dest
1179   
1180                # Find all build files first relatively to PBROOTDIR
1181                # Find also all specific files referenced in the .pb conf file
1182                my %bfiles = ();
1183                my %pkgfiles = ();
1184                # Used in Filter.pm by pb_filter_file
1185
1186                $build{$v} = "no";
1187                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'os'}") {
1188                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'os'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1189                    $build{$v} = "yes";
1190                } 
1191                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'type'}") {
1192                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'type'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1193                    $build{$v} = "yes";
1194                } 
1195                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'family'}") {
1196                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'family'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1197                    $build{$v} = "yes";
1198                } 
1199                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}") {
1200                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1201                    $build{$v} = "yes";
1202                } 
1203                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}") {
1204                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1205                    $build{$v} = "yes";
1206                } 
1207                if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") {
1208                    pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}",$pbpkg,\%bfiles,\%pkgfiles,$supfiles);
1209                    $build{$v} = "yes";
1210                }
1211                pb_log(2,"DEBUG($v) bfiles: ".Dumper(\%bfiles)."\n");
1212   
1213                if ($build{$v} ne "no") {
1214                    # Apply now all the filters on all the files concerned
1215                    # destination dir depends on the type of file
1216                    # For patch support
1217                    # TODO: Make it CMS aware
1218                    $pb->{'patches'} = pb_list_sfiles("$ENV{'PBROOTDIR'}/$pbpkg/pbpatch", $pb->{'patches'}, $pbos, "$ENV{'PBROOTDIR'}/$pbpkg/pbextpatch");
1219                    pb_log(2,"DEBUG($v) patches: ".Dumper($pb->{'patches'})."\n");
1220                    # TODO: Make it CMS aware
1221                    $pb->{'sources'} = pb_list_sfiles("$ENV{'PBROOTDIR'}/$pbpkg/pbsrc", $pb->{'sources'}, $pbos, "$ENV{'PBROOTDIR'}/$pbpkg/pbextsrc");
1222                    pb_log(2,"DEBUG($v) sources: ".Dumper($pb->{'sources'})."\n");
1223   
1224                    if (defined $pb->{'patches'}->{$v}) {
1225                        # Filter potential patches (local + remote)
1226                        pb_mkdir_p("$dest/pbconf/$v/pbpatch");
1227                        # If Debian based distribution, then prepare what will be done at build time
1228                        my ($patchcmd,$patchopt);
1229                        if ($pbos->{'type'} eq "deb") {
1230                            ($patchcmd,$patchopt) = pb_distro_get_param($pbos,pb_conf_get_if("ospatchcmd","ospatchopt"));
1231                            open(SCRIPT,"> $dest/pbconf/$v/pbpatch/pbapplypatch") || die "Unable to create $dest/pbconf/$v/pbpatch/pbapplypatch";
1232                            print SCRIPT "#!/bin/bash\n";
1233                            print SCRIPT "set -x\n" if ($pbdebug gt 1);
1234                        }
1235                        foreach my $pf (split(/,/,$pb->{'patches'}->{$v})) {
1236                            my $pp = basename($pf);
1237                            pb_vcs_export($pf,undef,"$dest/pbconf/$v/pbpatch");
1238                            pb_filter_file_inplace($ptr,"$dest/pbconf/$v/pbpatch/$pp",$pb);
1239                            pb_system("gzip -9f $dest/pbconf/$v/pbpatch/$pp","","quiet");
1240                            if ($pbos->{'type'} eq "deb") {
1241                                # If Debian based distribution, then prepare what will be done at build time
1242                                # by applying the patches that will be available under the debian/patches dir
1243                                print SCRIPT "$patchcmd $patchopt \< debian/patches/$pp\n";
1244                            }
1245                        }
1246                        if ($pbos->{'type'} eq "deb") {
1247                            close(SCRIPT);
1248                            chmod 0755,"$dest/pbconf/$v/pbpatch/pbapplypatch";
1249                        }
1250                        #pb_system("cat $dest/pbconf/$v/pbpatch/pbapplypatch","APPLY","verbose");
1251                    }
1252                    if (defined $pb->{'sources'}->{$v}) {
1253                        pb_mkdir_p("$dest/pbconf/$v/pbsrc");
1254                        foreach my $pf (split(/,/,$pb->{'sources'}->{$v})) {
1255                            my $pp = basename($pf);
1256                            pb_vcs_export($pf,undef,"$dest/pbconf/$v/pbsrc");
1257                            pb_filter_file_inplace($ptr,"$dest/pbconf/$v/pbsrc/$pp",$pb);
1258                        }
1259                    }
1260                    # Filter build files at the end, as they depend on patches and sources
1261                    foreach my $f (keys %bfiles) {
1262                        pb_filter_file("$ENV{'PBROOTDIR'}/$bfiles{$f}",$ptr,"$dest/pbconf/$v/$f",$pb);
1263                    }
1264                    foreach my $f (keys %pkgfiles) {
1265                        pb_filter_file("$ENV{'PBROOTDIR'}/$pkgfiles{$f}",$ptr,"$dest/pbconf/$v/$f",$pb);
1266                    }
1267                }
1268
1269                if (defined $pbparallel) {
1270                    # Communicate results back to parent
1271                    my $str = "";
1272                    $str .= "build $v = $build{$v}\n" if (defined $build{$v});
1273                    $str .= "patches $v = $pb->{'patches'}->{$v}\n" if (defined $pb->{'patches'}->{$v});
1274                    $str .= "sources $v = $pb->{'sources'}->{$v}\n" if (defined $pb->{'sources'}->{$v});
1275                    pb_set_content("$tmpd/$$","$str");
1276                    $pm->finish;
1277                }
1278            }
1279            # In the parent, we need to get the result from the children
1280            $pm->wait_all_children if (defined $pbparallel);
1281            die "Aborting, one or more of the children failed." if ((not $all_ok) && ($Global::pb_stop_on_error));
1282            my $made = "";
1283            my %h = ();
1284            my %tmp;
1285            my %tmp2;
1286            my $pt;
1287            my $k;
1288
1289            foreach $k (<$tmpd/*>) {
1290                $made .= pb_get_content($k);
1291            }
1292            pb_rm_rf($tmpd);
1293            pb_log(3,"MADE:\n$made");
1294
1295            # Rebuild local hashes
1296            foreach $k (split(/\n/,$made)) {
1297                if ($k =~ /^\s*([A-z0-9-_]+)\s+([[A-z0-9-_.]+)\s*=\s*(.+)$/) {
1298                    $h{$1}->{$2}=$3;
1299                }
1300            }
1301            pb_log(2,"HASH: ".Dumper(%h));
1302
1303            # Patches
1304            pb_log(0,"Delivered and compressed patches ");
1305            $pt = $h{'patches'};
1306            foreach $k (keys %$pt) {
1307                foreach my $v1 (split(/,/,$pt->{$k})) {
1308                    $tmp{$v1} = "";
1309                }
1310            }
1311            if (keys %tmp) {
1312                foreach $k (keys %tmp) {
1313                    pb_log(0,"$k ");
1314                }
1315            } else {
1316                pb_log(0,"N/A");
1317            }
1318            pb_log(0,"\n");
1319
1320            # Sources
1321            pb_log(0,"Delivered additional sources ");
1322            $pt = $h{'sources'};
1323            foreach $k (keys %$pt) {
1324                foreach my $v1 (split(/,/,$pt->{$k})) {
1325                    $tmp2{$v1} = "";
1326                }
1327            }
1328            if (keys %tmp2) {
1329                foreach $k (keys %tmp2) {
1330                    pb_log(0,"$k ");
1331                }
1332            } else {
1333                pb_log(0,"N/A");
1334            }
1335            pb_log(0,"\n");
1336
1337            # Build files
1338            my @found;
1339            my @notfound;
1340            $pt = $h{'build'};
1341            foreach my $b (keys %$pt) {
1342                push @found,$b if ($pt->{$b} =~ /yes/);
1343                push @notfound,$b if ($pt->{$b} =~ /no/);
1344            }
1345            pb_log(0,"Build files have been generated for ... ".join(',',sort(@found))."\n") if (@found);
1346            pb_log(0,"No Build files found for ".join(',',sort(@notfound))."\n") if (@notfound);
1347
1348        } else {
1349            # Instead call News generation
1350            pb_web_news2html($dest);
1351            # And create an empty pbconf
1352            pb_mkdir_p("$dest/pbconf");
1353            # And prepare the pbscript to execute remotely
1354            open(SCRIPT,"> $ENV{'PBTMP'}/pbscript") || die "Unable to create $ENV{'PBTMP'}/pbscript";
1355            print SCRIPT "#!/bin/bash\n";
1356            print SCRIPT "#set -x\n";
1357            print SCRIPT "echo ... Extracting Website content\n";
1358            print SCRIPT "find . -type f | grep -Ev '^./$pbpkg-$pbver$pbextdir.tar.gz|^./pbscript' | xargs rm -f non-existent\n";
1359            print SCRIPT "find * -type d -depth | xargs rmdir 2> /dev/null \n";
1360            print SCRIPT "tar xfz $pbpkg-$pbver$pbextdir.tar.gz\n";
1361            print SCRIPT "mv $pbpkg-$pbver$pbextdir/* .\n";
1362            print SCRIPT "rm -f $pbpkg-$pbver$pbextdir.tar.gz\n";
1363            print SCRIPT "rmdir $pbpkg-$pbver$pbextdir\n";
1364            print SCRIPT "find . -type f -print0 | xargs -0 chmod 644\n";
1365            print SCRIPT "find . -type d -print0 | xargs -0 chmod 755\n";
1366            close(SCRIPT);
1367            chmod 0755,"$ENV{'PBTMP'}/pbscript";
1368        }
1369
1370        # Apply filters to the non-build files
1371        my $liste ="";
1372        if (defined $filteredfiles->{$pbpkg}) {
1373            foreach my $f (split(/,/,$filteredfiles->{$pbpkg})) {
1374                pb_filter_file_inplace($ptr,"$dest/$f",$pb);
1375                $liste = "$f $liste";
1376            }
1377        }
1378        pb_log(2,"Files ".$liste."have been filtered\n");
1379
1380        # TODO: Make it CMS aware
1381        # Execute the pbinit script if any
1382        if (-x "$ENV{'PBROOTDIR'}/$pbpkg/pbinit") {
1383            pb_filter_file("$ENV{'PBROOTDIR'}/$pbpkg/pbinit",$ptr,"$ENV{'PBTMP'}/pbinit",$pb);
1384            chmod 0755,"$ENV{'PBTMP'}/pbinit";
1385            pb_system("cd $dest ; $ENV{'PBTMP'}/pbinit","Executing init script from $ENV{'PBROOTDIR'}/$pbpkg/pbinit under $dest","verbose");
1386        }
1387
1388        # Do we have additional script to run to prepare the environement for the project ?
1389        # Then include it in the pbconf delivery
1390        foreach my $pbvf (<$ENV{'PBROOTDIR'}/pbv*.pre>,<$ENV{'PBROOTDIR'}/pbv*.post>, <$ENV{'PBROOTDIR'}/pbtest*>) {
1391            if (-x "$pbvf") {
1392                my $target = "$ENV{'PBDESTDIR'}/".basename($pbvf);
1393                pb_filter_file("$pbvf",$ptr,$target,$pb);
1394                chmod 0755,"$target";
1395            }
1396        }
1397
1398        # Prepare the dest directory for archive
1399        chdir "$ENV{'PBDESTDIR'}" || die "Unable to change dir to $ENV{'PBDESTDIR'}";
1400        if (defined $preserve) {
1401            # In that case we want to preserve the original tar file for checksum purposes
1402            # The one created is btw equivalent in that case to this one
1403            # Maybe check basename of both to be sure they are the same ?
1404            pb_log(0,"Preserving original tar file ");
1405            move("$preserve","$pbpkg-$pbver$pbextdir.tar.gz");
1406        } else {
1407            # Possibility to look at PBSRC to guess more the filename
1408            pb_system("tar cfz $pbpkg-$pbver$pbextdir.tar.gz --exclude=$pbpkg-$pbver$pbextdir/pbconf $pbpkg-$pbver$pbextdir","Creating $pbpkg tar files compressed");
1409        }
1410        pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz\n");
1411        pb_system("tar cfz $pbpkg-$pbver$pbextdir.pbconf.tar.gz $pbpkg-$pbver$pbextdir/pbconf","Creating pbconf tar files compressed");
1412        pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz\n");
1413
1414        # Keep track of version-tag per pkg
1415        $pkgs{$pbpkg} = "$pbver-$pbtag";
1416
1417        # Final cleanup
1418        pb_rm_rf($dest) if (-d $dest);
1419    }
1420
1421    # Keep track of per package version
1422    pb_log(2,"DEBUG pkgs: ".Dumper(%pkgs)."\n");
1423    open(PKG,"> $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb") || die "Unable to create $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb";
1424    foreach my $pbpkg (keys %pkgs) {
1425        print PKG "pbpkg $pbpkg = $pkgs{$pbpkg}\n";
1426    }
1427    close(PKG);
1428
1429    # Keep track of what is generated by default
1430    # We need to store the dir and info on version-tag
1431    # Base our content on the existing .pb file
1432    copy("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb","$ENV{'PBDESTDIR'}/pbrc");
1433    open(LAST,">> $ENV{'PBDESTDIR'}/pbrc") || die "Unable to create $ENV{'PBDESTDIR'}/pbrc";
1434    print LAST "pbroot $ENV{'PBPROJ'} = $ENV{'PBROOTDIR'}\n";
1435    print LAST "projver $ENV{'PBPROJ'} = $ENV{'PBPROJVER'}\n";
1436    print LAST "projtag $ENV{'PBPROJ'} = $ENV{'PBPROJTAG'}\n";
1437    print LAST "pbpackager $ENV{'PBPROJ'} = $ENV{'PBPACKAGER'}\n";
1438    print LAST "pbextdir $ENV{'PBPROJ'} = $pbextdir\n";
1439    close(LAST);
1440}
1441
1442sub pb_test2pkg {
1443    # Get the running distro to test on
1444    my $pbos = pb_distro_get_context();
1445
1446    # Get list of packages to test
1447    # Get content saved in cms2build
1448    my $ptr = pb_get_pkg();
1449    @pkgs = @$ptr;
1450
1451    # Additional potential repo
1452    pb_distro_setuprepo($pbos);
1453    foreach my $pbpkg (@pkgs) {
1454        # We need to install the package to test, and deps brought with it
1455        pb_distro_installdeps(undef,$pbos,$pbpkg);
1456        pb_system("$ENV{'PBDESTDIR'}/pbtest","Launching test for $pbpkg","verbose");
1457    }
1458}
1459
1460sub pb_build2pkg {
1461
1462    my $do_install = shift;
1463
1464    pb_log(0,"INFO: ------ Starting to build package ------\n");
1465    # Get the running distro to build on
1466    my $pbos = pb_distro_get_context();
1467
1468    # If needed we may add repository to the build env
1469    pb_distro_setuprepo($pbos);
1470
1471    # Get list of packages to build
1472    my $ptr = pb_get_pkg();
1473    @pkgs = @$ptr;
1474
1475    # Get content saved in cms2build
1476    my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
1477    $pkg = { } if (not defined $pkg);
1478    my $pbextdir = pb_get_extdir();
1479
1480    pb_mkdir_p("$ENV{'PBBUILDDIR'}") if (! -d "$ENV{'PBBUILDDIR'}");
1481    chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
1482    my $made = ""; # pkgs made during build
1483    my $pm;
1484    my $all_ok = 1;
1485
1486    if (defined $pbparallel) {
1487        $pm = new Parallel::ForkManager($pbparallel);
1488        $pm->run_on_finish(sub { my ($pid, $code, $id, $signal, $dump) = @_;
1489                                $all_ok = 0 unless (($code == 0) && ($signal == 0) && ($dump == 0)); });
1490    }
1491
1492    # We need to communicate info back from the children if parallel so prepare a dir for that
1493    my $tmpd = "$ENV{'PBTMP'}/build.$$";
1494    pb_mkdir_p($tmpd) if (defined $pbparallel);
1495
1496    # Do it here as this doesn't work in // mode as itdies if it fails
1497    if ($pbos->{'type'} eq "rpm") {
1498        foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') {
1499                if (! -d "$ENV{'PBBUILDDIR'}/$d") {
1500                    pb_mkdir_p("$ENV{'PBBUILDDIR'}/$d");
1501                }
1502            }
1503    }
1504
1505    foreach my $pbpkg (@pkgs) {
1506        $pm->start and next if (defined $pbparallel);
1507
1508        my $vertag = $pkg->{$pbpkg};
1509        pb_log(2,"Vertag: $vertag\n");
1510        # get the version of the current package - maybe different
1511        ($pbver,$pbtag) = split(/-/,$vertag);
1512
1513        my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz";
1514        my $src2="$ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz";
1515        pb_log(2,"Source file: $src\n");
1516        pb_log(2,"Pbconf file: $src2\n");
1517
1518        pb_log(2,"Working directory: $ENV{'PBBUILDDIR'}\n");
1519        if ($pbos->{'type'} eq "rpm") {
1520            # Remove in case a previous link/file was there
1521            unlink "$ENV{'PBBUILDDIR'}/SOURCES/".basename($src);
1522            symlink "$src","$ENV{'PBBUILDDIR'}/SOURCES/".basename($src) || die "Unable to symlink $src in $ENV{'PBBUILDDIR'}/SOURCES";
1523            # We need to first extract the spec file
1524            my @specfile = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/","$ENV{'PBBUILDDIR'}/SPECS","spec");
1525
1526            # We need to handle potential patches to upstream sources
1527            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","$ENV{'PBBUILDDIR'}/SOURCES","patch");
1528
1529            # We need to handle potential additional sources to upstream sources
1530            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}/SOURCES","src");
1531
1532            pb_log(2,"specfile: ".Dumper(\@specfile)."\n");
1533            # set LANGUAGE to check for correct log messages
1534            $ENV{'LANGUAGE'}="C";
1535            # Older Redhat use _target_platform in %configure incorrectly
1536            my $specialdef = "";
1537            if (($pbos->{'name'} eq "rhel") && ($pbos->{'version'} eq "2.1")) {
1538                $specialdef = "--define \'_target_platform \"\"\'";
1539            }
1540            my $buildcmd = "rpmbuild";
1541            if (($pbos->{'name'} eq "redhat") && ($pbos->{'version'} =~ /^6/)){
1542                $buildcmd = "rpm" ;
1543            }
1544
1545            foreach my $f (@specfile) {
1546                if ($f =~ /\.spec$/) {
1547                    # This could cause an issue in // mode
1548                    pb_distro_installdeps($f,$pbos);
1549                    pb_system("$buildcmd $specialdef --define \"packager $ENV{'PBPACKAGER'}\" --define \"_topdir $ENV{'PBBUILDDIR'}\" -ba $f","Building package with $f under $ENV{'PBBUILDDIR'}","verbose");
1550                    last;
1551                }
1552            }
1553            # Get the name of the generated packages
1554            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
1555            while (<LOG>) {
1556                chomp($_);
1557                next if ($_ !~ /^Wrote:/);
1558                s|.*/([S]*RPMS.*)|$1|;
1559                $made .=" $_";
1560            }
1561            close(LOG);
1562
1563        } elsif ($pbos->{'type'} eq "deb") {
1564            pb_system("tar xfz $src","Extracting sources");
1565            pb_system("tar xfz $src2","Extracting pbconf");
1566
1567            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
1568            pb_rm_rf("debian");
1569            my $confdir = "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
1570            die "Configuration directory $confdir is not a directory\nIs os description listed in your {ve,vm,rm}list values?" if (not -d $confdir);
1571            symlink "$confdir","debian" || die "Unable to symlink 'debian' to $confdir";
1572            chmod 0755,"debian/rules";
1573
1574            # We need to handle potential patches to upstream sources
1575            pb_mkdir_p("debian/patches");
1576            my @f = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","debian/patches","patch");
1577
1578            # By default we use format 1.0 - Cf man dpkg-source
1579            my $debsrcfmt = "1.0";
1580            my $debsrcfile = "debian/source/format";
1581            if (-f $debsrcfile) {
1582                $debsrcfmt = pb_get_content($debsrcfile);
1583            }
1584
1585            if ($debsrcfmt =~ /^3.*quilt/) {
1586                # If we use quilt to manage patches, we then setup the env correctly
1587                # as per http://pkg-perl.alioth.debian.org/howto/quilt.html
1588                # Generate Debian patch series for quilt
1589                open(SERIE,"> debian/patches/series") || die "Unable to write in debian/patches/series";
1590                $ENV{'QUILT_PATCHES'}="debian/patches";
1591            } else {
1592                # If we use dpatch to manage patches, we then setup the 00list file as well
1593                open(SERIE,"> debian/patches/00list") || die "Unable to write in debian/patches/00list";
1594            }
1595            foreach my $f (sort @f) {
1596                # Skip the script made to apply the patches to the Debian tree
1597                next if ($f =~ /pbapplypatch/);
1598                # We also need to uncompress them
1599                pb_system("gzip -d $f","","quiet");
1600                $f =~ s/\.gz$//;
1601                print SERIE "$f\n";
1602            }
1603            close(SERIE);
1604            if (@f) {
1605                # We have patches...
1606                my $patch_file = "debian/patches/pbapplypatch";
1607                if (($debsrcfmt =~ /^1.*/) && (-x $patch_file)) {
1608                    # In that case we need to apply the patches ourselves locally
1609                    pb_system("cat $patch_file","APPLY","verbose");
1610                    pb_system("$patch_file","Applying patches to $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} tree");
1611                }
1612                # ...so modify the name of files to be Debian compliant
1613                move("../$src","../$pbpkg-$pbver$pbextdir.orig.tar.gz");
1614            }
1615
1616            # We need to handle potential additional sources to upstream sources
1617            #pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}/debian","src");
1618
1619            # This can create problems in // mode as well
1620            pb_distro_installdeps("debian/control",$pbos);
1621            pb_system("dpkg-buildpackage -us -uc -rfakeroot","Building package","verbose");
1622
1623            # Get the name of the generated packages
1624            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
1625            while (<LOG>) {
1626                chomp();
1627                pb_log(3,"In loop: $_\n");
1628                next unless (/^dpkg-deb.*\.\.\/(.*_.*\.deb).*/);
1629                my $tmp = $1;
1630                #doesn't work in my case
1631                #die "Missing file $tmp" if (not -f "../$tmp");
1632                $made = "$made $tmp";
1633            }
1634            close(LOG);
1635            pb_log(2,"Now made is: $made\n");
1636
1637            open(CTRL,"debian/control") || die "Unable to open debian/control: $!";
1638            while (<CTRL>) {
1639                pb_log(3,"In loop: $_\n");
1640                next unless (/^Source: (\S+)/o);
1641                my $tmp = $1;
1642                $made = "$made $tmp"."_*.dsc $tmp"."_*.tar.gz $tmp"."_*.changes";
1643                #doesn't work in my case
1644                #foreach my $glob (("$1\_*.changes", "$1\_*.dsc", "$1\_*.tar.gz")) {
1645                    #my @file = glob($glob);
1646                    #die "Missing file for $glob" unless (@file > 0);
1647                    #die "Too many files for $glob" if (@file > 1);
1648                    #die "Missing file $file[0]" if (not -f $file[0]);
1649                    #$made .= " $file[0]";
1650                #}
1651            }
1652            close(CTRL);
1653            #pb_display_file("$ENV{'PBTMP'}/system.$$.log");
1654            pb_log(2,"Finally made is: $made\n");
1655
1656            chdir ".." || die "Unable to chdir to parent dir";
1657            pb_rm_rf("$pbpkg-$pbver$pbextdir");
1658        } elsif ($pbos->{'type'} eq "ebuild") {
1659            my @ebuildfile;
1660            # For gentoo we need to take pb as subsystem name
1661            # We put every apps here under sys-apps. hope it's correct
1662            # We use pb's home dir in order to have a single OVERLAY line
1663            my $tmpe = "$ENV{'HOME'}/portage/pb/sys-apps/$pbpkg";
1664            pb_mkdir_p($tmpe) if (! -d "$tmpe");
1665            pb_mkdir_p("$ENV{'HOME'}/portage/distfiles") if (! -d "$ENV{'HOME'}/portage/distfiles");
1666
1667            # We need to first extract the ebuild file
1668            @ebuildfile = pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/","$tmpe","ebuild");
1669
1670            # Prepare the build env for gentoo
1671            my $found = 0;
1672            my $pbbd = $ENV{'HOME'};
1673            $pbbd =~ s|/|\\/|g;
1674            if (-r "/etc/make.conf") {
1675                open(MAKE,"/etc/make.conf");
1676                while (<MAKE>) {
1677                    $found = 1 if (/$pbbd\/portage/);
1678                }
1679                close(MAKE);
1680            }
1681            if ($found == 0) {
1682                pb_system("sudo sh -c 'echo PORTDIR_OVERLAY=\"$ENV{'HOME'}/portage\" >> /etc/make.conf'");
1683            }
1684            #$found = 0;
1685            #if (-r "/etc/portage/package.keywords") {
1686            #open(KEYW,"/etc/portage/package.keywords");
1687            #while (<KEYW>) {
1688            #$found = 1 if (/portage\/pb/);
1689            #}
1690            #close(KEYW);
1691            #}
1692            #if ($found == 0) {
1693            #pb_system("sudo sh -c \"echo portage/pb >> /etc/portage/package.keywords\"");
1694            #}
1695
1696            # Build
1697            foreach my $f (@ebuildfile) {
1698                if ($f =~ /\.ebuild$/) {
1699                    pb_distro_installdeps($f,$pbos);
1700                    move($f,"$tmpe/$pbpkg-$pbver.ebuild");
1701                    pb_system("cd $tmpe ; ebuild $pbpkg-$pbver.ebuild clean ; ebuild $pbpkg-$pbver.ebuild digest ; ebuild $pbpkg-$pbver.ebuild package","verbose");
1702                    # Now move it where pb expects it
1703                    pb_mkdir_p("$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg");
1704                    if ($pbtag eq 0) {
1705                        # This is assumed to be a test version
1706                        my $nver = substr($pbver,0,-14);
1707                        my $ntag = substr($pbver,-14);
1708                        my $ebtg = "portage/pb/sys-apps/$pbpkg/$pbpkg-$nver"."_p$ntag.ebuild";
1709                        move("$tmpe/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/$ebtg");
1710                        $made="$made $ebtg";
1711                    } else {
1712                        my $ebtg = "portage/pb/sys-apps/$pbpkg/$pbpkg-$pbver-r$pbtag.ebuild";
1713                        move("$tmpe/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/$ebtg");
1714                        $made="$made $ebtg";
1715                    }
1716                }
1717            }
1718
1719        } elsif ($pbos->{'type'} eq "tgz") {
1720            # Slackware family
1721            $made="$made $pbpkg/$pbpkg-$pbver-*-$pbtag.tgz";
1722
1723            pb_system("tar xfz $src","Extracting sources");
1724            pb_system("tar xfz $src2","Extracting pbconf");
1725            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
1726            symlink "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}","install" || die "Unable to symlink to pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
1727            if (-x "install/pbslack") {
1728                pb_distro_installdeps("./install/pbslack",$pbos);
1729                pb_system("./install/pbslack","Building software");
1730                pb_system("sudo /sbin/makepkg -p -l y -c y $pbpkg","Packaging $pbpkg","verbose");
1731            }
1732            chdir ".." || die "Unable to chdir to parent dir";
1733            pb_rm_rf("$pbpkg-$pbver$pbextdir");
1734        } elsif ($pbos->{'type'} eq "pkg") {
1735            # Solaris
1736            $made="$made $pbpkg-$pbver-$pbtag.pkg.gz";
1737            my $pkgdestdir="$ENV{'PBBUILDDIR'}/install";
1738
1739            # Will host resulting packages
1740            pb_mkdir_p("$pbos->{'type'}");
1741            pb_mkdir_p("$pkgdestdir/delivery");
1742            pb_system("tar xfz $src","Extracting sources under $ENV{'PBBUILDDIR'}");
1743            pb_system("tar xfz $src2","Extracting pbconf under $ENV{'PBBUILDDIR'}");
1744            # We need to handle potential patches to upstream sources
1745            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbpatch/","$ENV{'PBBUILDDIR'}","patch");
1746
1747            # We need to handle potential additional sources to upstream sources
1748            pb_extract_build_files($src2,"$pbpkg-$pbver$pbextdir/pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbsrc/","$ENV{'PBBUILDDIR'}","src");
1749
1750            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
1751            if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild") {
1752                chmod 0755,"pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild";
1753                # pkginfo file is mandatory
1754                die "Unable to find pkginfo file in pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}" if (! -f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pkginfo");
1755                # Build
1756                pb_system("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild $pkgdestdir/delivery","Building software and installing under $pkgdestdir/delivery");
1757                # Copy complementary files
1758                if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/prototype") {
1759                    copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/prototype", $pkgdestdir) 
1760                } else {
1761                    # No prototype provided, calculating it
1762                    open(PROTO,"> $pkgdestdir/prototype") || die "Unable to create prototype file";
1763                    print PROTO "i pkginfo\n";
1764                    print PROTO "i depend\n" if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend");
1765                    $ENV{'PBSOLDESTDIR'} = "$pkgdestdir/delivery";
1766                    find(\&create_solaris_prototype, "$pkgdestdir/delivery");
1767                }
1768                copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend", $pkgdestdir) if (-f "pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/depend");
1769                copy("pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pkginfo", $pkgdestdir);
1770                pb_system("cd $pkgdestdir/delivery ; pkgmk -o -f ../prototype -r $pkgdestdir/delivery -d $ENV{'PBBUILDDIR'}/$pbos->{'type'}","Packaging $pbpkg","verbose");
1771                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");
1772                pb_system("cd $ENV{'PBBUILDDIR'} ;  gzip -9f $pbpkg-$pbver-$pbtag.pkg","Compressing $pbpkg-$pbver-$pbtag.pkg","verbose");
1773            } else {
1774                pb_log(0,"No pbconf/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}/pbbuild file found for $pbpkg-$pbver in \n");
1775            }
1776            chdir ".." || die "Unable to chdir to parent dir";
1777            pb_rm_rf("$pbpkg-$pbver$pbextdir","$ENV{'PBBUILDDIR'}/$pbos->{'type'}","$pkgdestdir");
1778        } elsif ($pbos->{'type'} eq "hpux") {
1779            # HP-UX
1780            pb_system("tar xfz $src","Extracting sources");
1781            pb_system("tar xfz $src2","Extracting pbconf");
1782
1783            chdir "$pbpkg-$pbver$pbextdir" || die "Unable to chdir to $pbpkg-$pbver$pbextdir";
1784            pb_system("buildpackage ","Building package","verbose");
1785            # Get the name of the generated packages
1786            open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to open $ENV{'PBTMP'}/system.$$.log";
1787            while (<LOG>) {
1788                chomp();
1789                my $tmp = $_;
1790                next if ($tmp !~ /^SD BUILD.*:/);
1791                $tmp =~ s|.*../(.*)_(.*).sd.*|$1|;
1792                $made = "$made $tmp"."_*.sd";
1793            }
1794            close(LOG);
1795            $made="$made $pbpkg-$pbver-$pbtag.sd";
1796
1797            chdir ".." || die "Unable to chdir to parent dir";
1798            pb_rm_rf("$pbpkg-$pbver$pbextdir");
1799        } else {
1800            die "Unknown OS type format $pbos->{'type'}";
1801        }
1802        if (defined $pbparallel) {
1803            # Communicate results back to parent
1804            pb_set_content("$tmpd/$$",$made);
1805            $pm->finish;
1806        }
1807    }
1808    if (defined $pbparallel) {
1809        # In the parent, we need to get the result from the children
1810        $pm->wait_all_children;
1811        foreach my $f (<$tmpd/*>) {
1812            $made .= " ".pb_get_content($f);
1813        }
1814        die "Aborting, one or more of the children failed." if ((not $all_ok) && ($Global::pb_stop_on_error));
1815        pb_rm_rf($tmpd);
1816    }
1817
1818    # Sign packages
1819    pb_sign_pkgs($pbos,$made);
1820    pb_log(0,"INFO: ------ Finished building package ------\n");
1821
1822    # Find the appropriate check cmd/opts
1823    my ($chkcmd,$chkopt) = pb_distro_get_param($pbos,pb_conf_get_if("oschkcmd","oschkopt"));
1824
1825    my $ret = "";
1826    # Packages check if needed
1827    if ($pbos->{'type'} eq "rpm") {
1828        if ((defined  $chkcmd) && (-x $chkcmd)) {
1829            my $cmd = "$chkcmd";
1830            $cmd .= " $chkopt" if (defined $chkopt);
1831            $cmd .= " $made";
1832            my $ret = pb_system("$cmd","Checking validity of rpms with $chkcmd","mayfail");
1833            pb_log(0,"ERROR: when checking packages validity\n") if ($ret ne 0);
1834        }
1835        my $rpms ="";
1836        my $srpms ="";
1837        foreach my $f (split(/ /,$made)) {
1838            $rpms .= "$ENV{'PBBUILDDIR'}/$f " if ($f =~ /^RPMS\//);
1839            $srpms .= "$ENV{'PBBUILDDIR'}/$f " if ($f =~ /^SRPMS\//);
1840        }
1841        pb_log(0,"SRPM packages generated: $srpms\n");
1842        pb_log(0,"RPM packages generated: $rpms\n");
1843        $ret = $rpms;
1844    } elsif ($pbos->{'type'} eq "deb") {
1845        my $made2 = "";
1846        foreach my $f (split(/ /,$made)) {
1847            $made2 .= "$f " if ($f =~ /\.deb$/);
1848        }
1849        if ((defined  $chkcmd) && (-x $chkcmd)) {
1850            my $ret = pb_system("$chkcmd $chkopt $made2","Checking validity of debs with $chkcmd","mayfail");
1851            pb_log(0,"ERROR: when checking packages validity\n") if ($ret ne 0);
1852        }
1853        pb_log(0,"deb packages generated: $made2\n");
1854        $ret = $made2;
1855    } else {
1856        pb_log(0,"No check done for $pbos->{'type'} yet\n");
1857        pb_log(0,"Packages generated: $made\n");
1858        $ret = $made;
1859    }
1860
1861    # Keep track of what is generated so that we can get them back from VMs/RMs
1862    my $pbkeep = "$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}-$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
1863    open(KEEP,"> $pbkeep") || die "Unable to create $pbkeep: $!";
1864    print KEEP "$made\n";
1865    close(KEEP);
1866    pb_distro_installdeps(undef,$pbos,$ret) if ($do_install);
1867}
1868
1869sub create_solaris_prototype {
1870
1871    my $uidgid = "bin bin";
1872    my $pkgdestdir = $ENV{'PBSOLDESTDIR'};
1873
1874    return if ($_ =~ /^$pkgdestdir$/);
1875    if (-d $_) {
1876        my $n = $File::Find::name;
1877        $n =~ s~$pkgdestdir/~~;
1878        print PROTO "d none $n 0755 $uidgid\n";
1879    } elsif (-x $_) {
1880        my $n = $File::Find::name;
1881        $n =~ s~$pkgdestdir/~~;
1882        print PROTO "f none $n 0755 $uidgid\n";
1883    } elsif (-f $_) {
1884        my $n = $File::Find::name;
1885        $n =~ s~$pkgdestdir/~~;
1886        print PROTO "f none $n 0644 $uidgid\n";
1887    }
1888}
1889
1890sub pb_build2ssh {
1891    pb_send2target("Sources");
1892    pb_send2target("CPAN");
1893}
1894
1895sub pb_pkg2ssh {
1896    pb_send2target("Packages");
1897}
1898
1899# By default deliver to the the public site hosting the
1900# ftp structure (or whatever) or a VM/VE/RM
1901sub pb_send2target {
1902
1903    my $cmt = shift;
1904    my $v = shift || undef;
1905    my $vmexist = shift || 0;           # 0 is FALSE
1906    my $vmpid = shift || 0;             # 0 is FALSE
1907    my $snapme = shift || 0;            # 0 is FALSE
1908
1909    pb_log(2,"DEBUG: pb_send2target($cmt,".Dumper($v).",$vmexist,$vmpid)\n");
1910    my $host = "sshhost";
1911    my $login = "sshlogin";
1912    my $dir = "sshdir";
1913    my $port = "sshport";
1914    my $conf = "sshconf";
1915    my $tmout = undef;
1916    my $path = undef;
1917
1918    if ($cmt =~ /^VM/) {
1919        $login = "vmlogin";
1920        $dir = "pbdefdir";
1921        # Specific VM
1922        $tmout = "vmtmout";
1923        $path = "vmpath";
1924        $host = "vmhost";
1925        $port = "vmport";
1926    } elsif ($cmt =~ /^RM/) {
1927        $login = "rmlogin";
1928        $dir = "pbdefdir";
1929        # Specific RM
1930        $tmout = "rmtmout";
1931        $path = "rmpath";
1932        $host = "rmhost";
1933        $port = "rmport";
1934    } elsif ($cmt =~ /^VE/) {
1935        $login = "velogin";
1936        $dir = "pbdefdir";
1937        # Specific VE
1938        $path = "vepath";
1939        $conf = "rbsconf";
1940    } elsif ($cmt eq "Web") {
1941        $host = "websshhost";
1942        $login = "websshlogin";
1943        $dir = "websshdir";
1944        $port = "websshport";
1945    } elsif ($cmt eq "CPAN") {
1946        $host = "cpanpause";
1947        $login = "";
1948        $dir = "cpandir";
1949        $port = "";
1950    }
1951    my $cmd = "";
1952    my $src = "";
1953    my $cpanpkg = 0;
1954    my $pbos;
1955
1956    my $pbextdir = pb_get_extdir();
1957
1958    if ($cmt ne "Announce") {
1959        # Get list of packages to build
1960        my $ptr = pb_get_pkg();
1961        my @pkgs = ();
1962        @pkgs = @$ptr if (defined $ptr);
1963
1964        # Get the running distro to consider
1965        $pbos = pb_distro_get_context($v);
1966
1967        my $pkg = { };
1968        # Get content saved in cms2build
1969        if ((defined $ENV{'PBDESTDIR'}) && (defined $ENV{'PBPROJVER'}) && (defined $ENV{'PBPROJTAG'}) && (-f "$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb")) {
1970            ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
1971            $pkg = { } if (not defined $pkg);
1972        }
1973
1974        pb_mkdir_p("$ENV{'PBBUILDDIR'}") if (! -d "$ENV{'PBBUILDDIR'}");
1975        chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}";
1976        foreach my $pbpkg (@pkgs) {
1977            my $vertag = $pkg->{$pbpkg};
1978            # get the version of the current package - maybe different
1979            pb_log(2,"Vertag: $vertag\n");
1980            ($pbver,$pbtag) = split(/-/,$vertag);
1981
1982            if (($cmt eq "Sources") || ($cmt =~ /(V[EM]|RM)build/)) {
1983                $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.pbconf.tar.gz";
1984                if ($cmd eq "") {
1985                    $cmd = "ln -sf $pbpkg-$pbver$pbextdir.tar.gz $pbpkg-latest.tar.gz";
1986                } else {
1987                    $cmd = "$cmd ; ln -sf $pbpkg-$pbver$pbextdir.tar.gz $pbpkg-latest.tar.gz";
1988                }
1989            } elsif ($cmt eq "Web") {
1990                $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver$pbextdir.tar.gz"
1991            }
1992
1993            # Do we have one perl package
1994            my @nametype = pb_conf_get_if("namingtype");
1995            my $type = $nametype[0]->{$pbpkg};
1996            if ((defined $type) && ($type eq "perl")) {
1997                $cpanpkg = 1;
1998            }
1999        }
2000        # Adds conf file for availability of conf elements
2001        pb_conf_add("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb") if ((defined $ENV{'PBROOTDIR'}) && (-f "$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"));
2002    }
2003    my ($rbsconf,$testver,$delivery) = pb_conf_get_if($conf,"testver","delivery");
2004    if ($cmt eq "CPAN") {
2005        # Do not deliver on Pause if this is a test version
2006        return if (not defined $testver);
2007        return if ($testver =~ /true/);
2008        # Do not deliver on Pause if this is not a perl package
2009        return if ($cpanpkg == 0);
2010    }
2011
2012    if ($cmt =~ /(V[EM]|RM)build/) {
2013        $src="$src $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb $ENV{'PBETC'} $ENV{'PBDESTDIR'}/pbrc $ENV{'PBDESTDIR'}/pbscript.$$";
2014    } elsif ($cmt =~ /(V[EM]|RM)Script/) {
2015        $src="$src $ENV{'PBDESTDIR'}/pbscript.$$";
2016    } elsif ($cmt =~ /(V[EM]|RM)test/) {
2017        $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";
2018    } elsif (($cmt eq "Announce") || ($cmt eq "Web") || ($cmt eq "CPAN")) {
2019        $src="$src $ENV{'PBTMP'}/pbscript";
2020    } elsif ($cmt eq "Packages") {
2021        # Get package list from file made during build2pkg
2022        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'}";
2023        $src = <KEEP>;
2024        chomp($src);
2025        close(KEEP);
2026        $src = "$src $ENV{'PBBUILDDIR'}/pbscript.$$";
2027    }
2028    if (($cmt eq "Sources") || ($cmt eq "Packages") || ($cmt eq "CPAN")) {
2029        my ($pbpackager) = pb_conf_get("pbpackager");
2030        $ENV{'PBPACKAGER'} = $pbpackager->{$ENV{'PBPROJ'}};
2031        pb_log(0,"Exporting public key for $ENV{'PBPACKAGER'}\n");
2032        # Using pb_system is not working due to redirection below
2033        system("gpg --export -a \'$ENV{'PBPACKAGER'}\' > $ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey");
2034        chmod 0644,"$ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey";
2035        $src = "$src $ENV{'PBDESTDIR'}/$ENV{'PBPROJ'}.pubkey";
2036    }
2037    # Remove potential leading spaces (cause problem with basename)
2038    $src =~ s/^ *//;
2039    my $basesrc = "";
2040    foreach my $i (split(/ +/,$src)) {
2041        $basesrc .= " ".basename($i);
2042    }
2043
2044    pb_log(0,"Sources handled ($cmt): $src\n");
2045    pb_log(2,"values: ".Dumper(($host,$login,$dir,$port,$tmout,$path,$conf))."\n");
2046    my ($sshhost,$sshdir) = pb_conf_get($host,$dir);
2047    # Not mandatory...
2048    $delivery->{$ENV{'PBPROJ'}} = "" if (not defined $delivery->{$ENV{'PBPROJ'}});
2049    my ($sshlogin,$sshport) = pb_conf_get_if($login,$port);
2050    $sshport->{$ENV{PBPROJ}} = 22 if (not defined $sshport->{$ENV{PBPROJ}});
2051    $sshlogin->{$ENV{PBPROJ}} = getpwuid($UID) if (not defined $sshlogin->{$ENV{PBPROJ}});
2052    my ($vtmout,$vepath);
2053    # ...Except those in virtual context
2054    if ($cmt =~ /^VE/) {
2055        ($vepath) = pb_conf_get($path);
2056    }
2057    if ($cmt =~ /^(V|R)M/) {
2058        $vtmout = pb_distro_get_param($pbos,pb_conf_get_if($tmout));
2059    }
2060    my $remhost = $sshhost->{$ENV{'PBPROJ'}};
2061    my $remdir = $sshdir->{$ENV{'PBPROJ'}};
2062    if ($cmt =~ /^V[EM]|RM/) {
2063        # In that case our real host is in the xxhost with the OS as key, not project as above
2064        $remhost = pb_distro_get_param($pbos,$sshhost);
2065    }
2066    pb_log(2,"ssh: ".Dumper(($remhost,$sshlogin,$remdir,$sshport,$vepath,$rbsconf))."\n");
2067    pb_log(2,"ssh: ".Dumper($vtmout)."\n") if (defined $vtmout);
2068
2069    my $mac;
2070    if ($cmt !~ /^VE/) {
2071        $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$remhost";
2072        # Overwrite account value if passed as parameter
2073        $mac = "$pbaccount\@$remhost" if (defined $pbaccount);
2074        pb_log(2, "DEBUG: pbaccount: $pbaccount => mac: $mac\n") if (defined $pbaccount);
2075    } else {
2076        # VE
2077        # Overwrite account value if passed as parameter (typically for setup2v)
2078        $mac = $sshlogin->{$ENV{'PBPROJ'}};
2079        $mac = $pbaccount if (defined $pbaccount);
2080    }
2081
2082    my $tdir;
2083    my $bdir;
2084    if (($cmt eq "Sources") || ($cmt =~ /(V[EM]|RM)Script/)) {
2085        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/src";
2086    } elsif ($cmt eq "CPAN") {
2087        $tdir = "$remdir";
2088    } elsif ($cmt =~ /(V[EM]|RM)(build|test)/) {
2089        $tdir = $remdir."/$ENV{'PBPROJ'}/delivery";
2090        $bdir = $remdir."/$ENV{'PBPROJ'}/build";
2091        # Remove a potential $ENV{'HOME'} as bdir should be relative to pb's home
2092        $bdir =~ s|\$ENV.+\}/||;
2093    } elsif ($cmt eq "Announce") {
2094        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}";
2095    } elsif ($cmt eq "Web") {
2096        $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}";
2097    } elsif ($cmt eq "Packages") {
2098        if (($pbos->{'type'} eq "rpm") || ($pbos->{'type'} eq "pkg") || ($pbos->{'type'} eq "hpux") || ($pbos->{'type'} eq "tgz")) {
2099            # put packages under an arch subdir
2100            $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}";
2101        } elsif (($pbos->{'type'} eq "deb") || ($pbos->{'type'} eq "ebuild")) {
2102            # No need for an arch subdir
2103            $tdir = "$remdir/$delivery->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}";
2104        } else {
2105            die "Please teach the dev team where to deliver ($pbos->{'type'} type of packages\n";
2106        }
2107
2108        my $repodir = $tdir;
2109        $repodir =~ s|^$remdir/||;
2110        my $repotag = "";
2111        $repotag = "-$delivery->{$ENV{'PBPROJ'}}" if ($delivery->{$ENV{'PBPROJ'}} ne "");
2112
2113        my ($pbrepo) = pb_conf_get("pbrepo");
2114
2115        # Repository management
2116        open(PBS,"> $ENV{'PBBUILDDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBBUILDDIR'}/pbscript.$$";
2117        if ($pbos->{'type'} eq "rpm") {
2118            my $pbsha = pb_distro_get_param($pbos,pb_conf_get("ossha"));
2119            my $gpgcheck = pb_conf_get_if("pbgpgcheck");
2120            my $pbgpgcheck;
2121            $pbgpgcheck = $gpgcheck->{$ENV{PBPROJ}} if (defined $gpgcheck);
2122            # By default force GPG check in repo even if we support signature of packages to fail. This is a best practice
2123            $pbgpgcheck = 1 if (not defined $pbgpgcheck);
2124            # Also make a pbscript to generate yum/urpmi bases
2125            print PBS << "EOF";
2126#!/bin/bash
2127# Prepare a script to ease yum setup
2128EOF
2129            print PBS "set -x\n" if ($pbdebug gt 1);
2130            print PBS << "EOF";
2131cat > $ENV{'PBPROJ'}$repotag.repo << EOT
2132[$ENV{'PBPROJ'}$repotag]
2133name=$pbos->{'name'} $pbos->{'version'} $pbos->{'arch'} - $ENV{'PBPROJ'} Vanilla Packages
2134baseurl=$pbrepo->{$ENV{'PBPROJ'}}/$repodir
2135enabled=1
2136gpgcheck=$pbgpgcheck
2137gpgkey=$pbrepo->{$ENV{'PBPROJ'}}/$repodir/$ENV{'PBPROJ'}.pubkey
2138EOT
2139chmod 644 $ENV{'PBPROJ'}$repotag.repo
2140
2141# Clean up old repo content
2142rm -rf headers/ repodata/
2143# Create yum repo
2144if [ -x /usr/bin/yum-arch ]; then
2145    yum-arch .
2146fi
2147# Create repodata
2148createrepo -s $pbsha .
2149# Link to the key
2150if [ -s $ENV{'PBPROJ'}.pubkey ]; then
2151    # Avoiding creating empty repomd.xml.key; fails on opensuse 12.1
2152    (cd repodata ; ln -sf ../$ENV{'PBPROJ'}.pubkey repomd.xml.key)
2153fi
2154# sign the repomd (at least useful for SLES - which requires a local key)
2155# gpg -a --detach-sign repodata/repomd.xml
2156# SLES also looks for media.1/info.txt
2157EOF
2158            if ($pbos->{'family'} eq "md") {
2159                # For Mandriva add urpmi management
2160                print PBS << "EOF";
2161# Prepare a script to ease urpmi setup
2162cat > $ENV{'PBPROJ'}$repotag.addmedia << EOT
2163urpmi.addmedia $ENV{'PBPROJ'}$repotag $pbrepo->{$ENV{'PBPROJ'}}/$repodir with media_info/hdlist.cz
2164EOT
2165chmod 755 $ENV{'PBPROJ'}$repotag.addmedia
2166
2167# Clean up old repo content
2168rm -f hdlist.cz synthesis.hdlist.cz
2169# Create urpmi repo
2170genhdlist2 --clean .
2171if [ \$\? -ne 0 ]; then
2172    genhdlist .
2173fi
2174EOF
2175            }
2176            if ($pbos->{'name'} eq "fedora") {
2177                # Extract the spec file to please Fedora maintainers :-(
2178                print PBS << "EOF";
2179for p in $basesrc; do
2180    echo \$p | grep -q 'src.rpm'
2181    if [ \$\? -eq 0 ]; then
2182        rpm2cpio \$p | cpio -ivdum --quiet '*.spec'
2183    fi
2184done
2185EOF
2186            }
2187            if ($pbos->{'family'} eq "novell") {
2188                # Add ymp scripts for one-click install on SuSE
2189                print PBS << "EOF";
2190# Prepare a script to ease SuSE one-click install
2191# Cf: http://de.opensuse.org/1-Klick-Installation/ISV
2192#
2193cat > $ENV{'PBPROJ'}$repotag.ymp << EOT
2194<?xml version="1.0" encoding="utf-8"?>
2195<!-- vim: set sw=2 ts=2 ai et: -->
2196<metapackage xmlns:os="http://opensuse.org/Standards/One_Click_Install" xmlns="http://opensuse.org/Standards/One_Click_Install">
2197    <group><!-- The group of software, typically one for project-builder.org -->
2198        <name>$ENV{'PBPROJ'} Bundle</name> <!-- Name of the software group -->
2199        <summary>Software bundle for the $ENV{'PBPROJ'}$repotag project</summary> <!--This message is shown to the user and should describe the whole bundle -->
2200        <description>This is the summary of the $ENV{'PBPROJ'}$repotag Project
2201             
2202            Details are available on a per package basis below
2203
2204        </description><!--This is also shown to the user -->
2205        <remainSubscribed>false</remainSubscribed> <!-- Don't know what it mean -->
2206        <repositories><!-- List of needed repositories -->
2207            <repository>
2208                <name>$ENV{'PBPROJ'}$repotag Repository</name> <!-- Name of the repository  -->
2209                <summary>This repository contains the $ENV{'PBPROJ'}$repotag project packages.</summary> <!-- Summary of the repository -->
2210                <description>This repository contains the $ENV{'PBPROJ'}$repotag project packages.</description><!-- This description is shown to the user -->
2211                <url>$pbrepo->{$ENV{'PBPROJ'}}/$repodir</url><!--URL of repository, which is added -->
2212            </repository>
2213        </repositories>
2214        <software><!-- A List of packages, which should be added through the one-click-installation -->
2215EOT
2216for p in $basesrc; do
2217    sum=`rpm -q --qf '%{SUMMARY}' \$p`
2218    name=`rpm -q --qf '%{NAME}' \$p`
2219    desc=`rpm -q --qf '%{description}' \$p`
2220    cat >> $ENV{'PBPROJ'}$repotag.ymp << EOT
2221            <item>
2222                <name>\$name</name><!-- Name of the package, is shown to the user and used to identify the package at the repository -->
2223                <summary>\$sum</summary> <!-- Summary of the package -->
2224                <description>\$desc</description> <!-- Description, is shown to the user -->
2225            </item>
2226EOT
2227done
2228cat >> $ENV{'PBPROJ'}$repotag.ymp << EOT
2229        </software>
2230    </group>
2231</metapackage>
2232EOT
2233chmod 644 $ENV{'PBPROJ'}$repotag.ymp
2234EOF
2235            }
2236        } elsif ($pbos->{'type'} eq "deb") {
2237            # Also make a pbscript to generate apt bases
2238            # Cf: http://www.debian.org/doc/manuals/repository-howto/repository-howto.fr.html
2239            # This dirname removes ver
2240            my $debarch = $pbos->{'arch'};
2241            $debarch = "amd64" if ($pbos->{'arch'} eq "x86_64");
2242            my $rpd = dirname("$pbrepo->{$ENV{'PBPROJ'}}/$repodir");
2243            # Remove extra . in path to fix #522
2244            $rpd =~ s|/./|/|g;
2245            my ($projcomponent_map) = pb_conf_get_if("projcomponent");
2246            pb_log(2,"projcomponent = ".Dumper($projcomponent_map)."\n");
2247            my $projcomponent = $projcomponent_map->{$ENV{PBPROJ}};
2248            $projcomponent ||= 'contrib';
2249            print PBS << "EOF";
2250#!/bin/bash
2251# Prepare a script to ease apt setup
2252cat > $ENV{'PBPROJ'}$repotag.sources.list << EOT
2253deb $rpd $pbos->{'version'} $projcomponent
2254deb-src $rpd $pbos->{'version'} $projcomponent
2255EOT
2256chmod 644 $ENV{'PBPROJ'}$repotag.sources.list
2257
2258# Up two levels to deal with the dist dir cross versions
2259cd ..
2260mkdir -p dists/$pbos->{'version'}/$projcomponent/binary-$debarch dists/$pbos->{'version'}/$projcomponent/source
2261
2262# Prepare a script to create apt info file
2263# Reuse twice after
2264TMPD=`mktemp -d /tmp/pb.XXXXXXXXXX` || exit 1
2265mkdir -p \$TMPD
2266cat > \$TMPD/Release << EOT
2267Archive: unstable
2268Component: $projcomponent
2269Origin: $ENV{'PBPROJ'}$repotag
2270Label: $ENV{'PBPROJ'}$repotag dev repository $pbrepo->{$ENV{'PBPROJ'}}
2271EOT
2272
2273echo "Creating Packages metadata"
2274for i in dists/$pbos->{version}/$projcomponent/binary-*; do
2275    arch=`basename \$i | sed 's/binary-//'`
2276    echo "Packages for \$arch:"
2277    dpkg-scanpackages -a\$arch $pbos->{'version'} /dev/null > dists/$pbos->{'version'}/$projcomponent/binary-\$arch/Packages
2278    gzip -9 < dists/$pbos->{'version'}/$projcomponent/binary-\$arch/Packages > dists/$pbos->{'version'}/$projcomponent/binary-\$arch/Packages.gz
2279    bzip2 -9 < dists/$pbos->{'version'}/$projcomponent/binary-\$arch/Packages > dists/$pbos->{'version'}/$projcomponent/binary-\$arch/Packages.bz2
2280done
2281echo "Creating Contents metadata"
2282apt-ftparchive contents $pbos->{'version'} | gzip -c9 > dists/$pbos->{'version'}/Contents.gz
2283echo "Creating Release metadata ($pbos->{'arch'} aka $debarch)"
2284cat \$TMPD/Release > dists/$pbos->{'version'}/$projcomponent/binary-$debarch/Release
2285echo "Architecture: $debarch" >> dists/$pbos->{'version'}/$projcomponent/binary-$debarch/Release
2286echo "Creating Source metadata"
2287dpkg-scansources $pbos->{'version'} /dev/null > dists/$pbos->{'version'}/$projcomponent/source/Sources
2288gzip -9 < dists/$pbos->{'version'}/$projcomponent/source/Sources > dists/$pbos->{'version'}/$projcomponent/source/Sources.gz
2289bzip2 -9 < dists/$pbos->{'version'}/$projcomponent/source/Sources > dists/$pbos->{'version'}/$projcomponent/source/Sources.bz2
2290cat \$TMPD/Release > dists/$pbos->{'version'}/$projcomponent/source/Release
2291echo "Architecture: Source" >> dists/$pbos->{'version'}/$projcomponent/source/Release
2292echo "Creating Release metadata"
2293# Signing that file would be useful but uneasy as gpg keys are not there
2294# Cf: http://wiki.debian.org/SecureApt
2295# Same as for repomd
2296apt-ftparchive -o APT::FTPArchive::Release::Suite=$pbos->{version} release dists/$pbos->{'version'} > dists/$pbos->{'version'}/Release
2297rm -rf \$TMPD
2298EOF
2299        } elsif ($pbos->{'type'} eq "ebuild") {
2300            # make a pbscript to generate links to latest version
2301            print PBS << "EOF";
2302#!/bin/bash
2303# Prepare a script to create correct links
2304for p in $src; do
2305    echo \$p | grep -q '.ebuild'
2306    if [ \$\? -eq 0 ]; then
2307        j=`basename \$p`
2308        pp=`echo \$j | cut -d'-' -f1`
2309        ln -sf \$j \$pp.ebuild
2310    fi
2311done
2312EOF
2313        }
2314        close(PBS);
2315        chmod 0755,"$ENV{'PBBUILDDIR'}/pbscript.$$";
2316    } else {
2317        return;
2318    }
2319
2320    # Useless for VE
2321    my $nport = pb_get_port($sshport,$pbos,$cmt) if ($cmt !~ /^VE/);
2322
2323    # Remove a potential $ENV{'HOME'} as tdir should be relative to pb's home
2324    if ($cmt =~ /^VE/o) {
2325        $tdir =~ s|\$ENV.+\}/|| or confess "for $cmt: $tdir must have \$ENV{'HOME'} in it or the remainder of the code won't work since some parts use relative pathing and others will try absolute.  Use a symlink if necessary to place the real files in a different place than under your home directory";
2326    } else {
2327        # process, ok if not present.
2328        $tdir =~ s|\$ENV.+\}/||;
2329    }
2330
2331    my $tm = "";
2332    if ($cmt =~ /^(V|R)M/) {
2333        $tm = "sleep $vtmout" if (defined $vtmout);
2334    }
2335
2336    # ssh communication if not VE or CPAN
2337    # should use a hash instead...
2338    my ($shcmd,$shcmdroot,$cpcmd,$cptarget,$cp2target);
2339    my $tpdir;
2340    if ($cmt =~ /^VE/) {
2341        my $tp = pb_path_expand($vepath->{$ENV{'PBPROJ'}});
2342        $tpdir = pb_path_expand("$tp/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
2343        my ($ptr) = pb_conf_get("vetype");
2344        my $vetype = $ptr->{$ENV{'PBPROJ'}};
2345        my $arch = pb_get_arch();
2346        if ($vetype eq "chroot") {
2347            $shcmdroot = "sudo /usr/sbin/chroot $tpdir ";
2348            $shcmd = "$shcmdroot /bin/su - $mac -c ";
2349        } elsif ($vetype eq "schroot") {
2350            $shcmd = "schroot $tp -u $mac -- ";
2351        }
2352        $shcmd = "setarch i386 $shcmd" if (($pbos->{'arch'} =~ /i[3456]86/) && ($arch eq 'x86_64'));
2353        $cpcmd = "sudo /bin/cp -r ";
2354        # We need to get the home dir of the target account to deliver in the right place
2355        open(PASS,"$tpdir/etc/passwd") || die "Unable to open $tpdir/etc/passwd: $!";
2356        my $homedir = "";
2357        while (<PASS>) {
2358            my ($c1,$c2,$c3,$c4,$c5,$c6,$c7) = split(/:/);
2359            $homedir = $c6 if ($c1 =~ /^$mac$/);
2360            pb_log(3,"Homedir: $homedir - account: $c6\n");
2361        }
2362        close(PASS);
2363        $cptarget = "$tpdir/$homedir/$tdir";
2364        if ($cmt eq "VEbuild") {
2365            $cp2target = "$tpdir/$homedir/$bdir";
2366        }
2367        pb_log(2,"On VE using $cptarget as target dir to copy to\n");
2368    } elsif ($cmt eq "CPAN") {
2369        my $ftpput = pb_check_req("ncftpput",1);
2370        my $ftpget = pb_check_req("wget",1);
2371        my ($cpanuser,$cpanpasswd) = pb_conf_get_if("cpanuser","cpanpasswd");
2372        return if ((not defined $cpanuser) || (not defined $cpanuser->{$ENV{'PBPROJ'}}));
2373        return if ((not defined $cpanpasswd) || (not defined $cpanpasswd->{$ENV{'PBPROJ'}}));
2374        my ($cpansubdir) = pb_conf_get_if("cpansubdir");
2375        $shcmd = "$ftpget --post-data \'HIDDENNAME=".$cpanuser->{$ENV{'PBPROJ'}};
2376        $shcmd .= "&user=".$cpanuser->{$ENV{'PBPROJ'}};
2377        $shcmd .= "&password=".$cpanpasswd->{$ENV{'PBPROJ'}};
2378        $shcmd .= "&SUBMIT_pause99_add_uri_upload=\"Upload the checked files\"";
2379        $shcmd .= "&pause99_add_uri_subdirtext=".$cpansubdir->{$ENV{'PBPROJ'}} if ((defined $cpansubdir) && (defined $cpansubdir->{$ENV{'PBPROJ'}}));
2380        foreach my $s (split(/ /,$src)) {
2381            $shcmd .= "&pause99_add_uri_upload=".basename($s);
2382        }
2383        $shcmd .= "'";
2384        $cpcmd = "$ftpput $host $dir";
2385        $cptarget = "CPAN";
2386    } else {
2387        my $keyfile = pb_ssh_get(0);
2388        my $keyopt = "";
2389        $keyopt = "-i $keyfile" if ((defined $keyfile) && ($cmt !~ /Packages/));
2390        my $sshcmd = pb_check_req("ssh",1);
2391        my $scpcmd = pb_check_req("scp",1);
2392        $shcmd = "$sshcmd $keyopt -q -o NoHostAuthenticationForLocalhost=yes -p $nport $mac";
2393        $cpcmd = "$scpcmd $keyopt -p -o NoHostAuthenticationForLocalhost=yes -P $nport";
2394        $cptarget = "$mac:$tdir";
2395        if ($cmt =~ /^(V|R)Mbuild/) {
2396            $cp2target = "$mac:$bdir";
2397        }
2398    }
2399   
2400    my $logres = "";
2401    # Do not touch when just announcing
2402    if (($cmt ne "Announce") && ($cmt ne "CPAN")) {
2403        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 -e\"","Preparing $tdir on $cptarget");
2404    } else {
2405        $logres = "> ";
2406    }
2407    pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget");
2408
2409    my $chowncommand = pb_check_req("chown",0);
2410    # For VE we need to change the owner manually
2411    if ($cmt =~ /^VE/) {
2412        my $sudomode = pb_distro_get_param($pbos,pb_conf_get("ossudoersmode"));
2413        my $res = pb_system("$shcmdroot sed -i '/requiretty/d' /etc/sudoers","Removing potential requiretty in sudoers","quiet");
2414        pb_system("$shcmdroot sed '/requiretty/d' /etc/sudoers > /tmp/sudoers.new ; mv /tmp/sudoers.new $tpdir/tmp/sudoers.new ; $shcmdroot mv /tmp/sudoers.new /etc/sudoers ; $shcmdroot chown root:root /etc/sudoers ; $shcmdroot chmod $sudomode /etc/sudoers","Removing again potential requiretty in sudoers as sed -i failed") if (($res ne 0) && (-f "$tpdir/etc/sudoers"));
2415        pb_system("$shcmd \"sudo $chowncommand -R $mac $tdir\"","Adapt owner in $tdir to $mac");
2416    }
2417
2418    # Use the right script name depending on context
2419    my $pbscript;
2420    if (($cmt =~ /^(V[EM]|RM)/) || ($cmt =~ /Packages/)){
2421        $pbscript = "pbscript.$$";
2422    } else {
2423        $pbscript = "pbscript";
2424    }
2425
2426    # It's already ready for CPAN
2427    my $shcmdbase = $shcmd;
2428    if ($cmt ne "CPAN") {
2429        $shcmd .= " \"echo \'cd $tdir ; if [ -x $pbscript ]; then ./$pbscript; fi ; rm -f ./$pbscript\' | bash\"";
2430    }
2431    my $cmdverb = "verbose";
2432    if (($cmt eq "Announce") || ($cmt eq "CPAN")) {
2433        $cmdverb = undef;
2434    } elsif (defined ($v)) {
2435        $cmdverb = "verbose_\[$v\] ";
2436    }
2437    pb_system("$shcmd","Executing pbscript on $cptarget if needed",$cmdverb);
2438    if ($cmt =~ /^(V[EM]|RM)build/) {
2439        # Get back info on pkg produced, compute their name and get them from the VM/RM
2440        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");
2441        if (not -f "$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$") {
2442            pb_log(0,"ERROR with VM/RM $v on getting $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$\n");
2443        } else {
2444            open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$";
2445            my $src = <KEEP>;
2446            chomp($src);
2447            close(KEEP);
2448            unlink("$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.$$");
2449
2450            $src =~ s/^ *//;
2451            pb_mkdir_p("$ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
2452            # Change pgben to make the next send2target happy
2453            my $made = "";
2454   
2455            # For VM/RM we don't want shell expansion to hapen locally but remotely
2456            my $delim = '\'';
2457            if ($cmt =~ /^VEbuild/) {
2458                # For VE we need to support shell expansion locally
2459                $delim = "";
2460            }   
2461
2462            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'}";
2463            foreach my $p (split(/ +/,$src)) {
2464                my $j = basename($p);
2465                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'}");
2466                $made="$made $pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/$j"; # if (($pbos->{'type'} ne "rpm") || ($j !~ /.src.rpm$/));
2467            }
2468            print KEEP "$made\n";
2469            close(KEEP);
2470            pb_system("$shcmdbase \"rm -rf $tdir $bdir\"","$cmt cleanup");
2471
2472            # Sign packages locally
2473            pb_sign_pkgs($pbos,$made);
2474
2475            # We want to send them to the ssh account so overwrite what has been done before
2476            undef $pbaccount;
2477            pb_log(2,"Before sending pkgs, vmexist: $vmexist, vmpid: $vmpid\n");
2478            pb_send2target("Packages",$pbos->{'name'}."-".$pbos->{'version'}."-".$pbos->{'arch'},$vmexist,$vmpid);
2479            pb_rm_rf("$ENV{'PBBUILDDIR'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
2480        }
2481    }
2482    unlink("$ENV{'PBDESTDIR'}/pbscript.$$") if ((($cmt =~ /^(V[ME]|RM)/) || ($cmt =~ /Packages/)) && ($pbkeep eq 0));
2483
2484    pb_log(2,"Before halt, vmexist: $vmexist, vmpid: $vmpid\n");
2485    if ((! $vmexist) && ($cmt =~ /^VM/)) {
2486        # If in setupvm then takes a snapshot just before halting
2487        if ($snapme != 0) {
2488            my ($vmmonport,$vmtype) = pb_conf_get("vmmonport","vmtype");
2489            # For monitoring control
2490            if ((($vmtype->{$ENV{'PBPROJ'}}) eq "kvm") || (($vmtype->{$ENV{'PBPROJ'}}) eq "qemu")) {
2491                eval
2492                {
2493                require Net::Telnet;
2494                Net::Telnet->import();
2495                };
2496                if ($@) {
2497                    # Net::Telnet not found
2498                    pb_log(1,"ADVISE: Install Net::Telnet to benefit from monitoring control and snapshot feature.\nWARNING: No snapshot created");
2499                } else {
2500                    my $t = new Net::Telnet (Timeout => 120, Host => "localhost", Port => $vmmonport->{$ENV{'PBPROJ'}}) || die "Unable to dialog on the monitor";
2501                    # move to monitor mode
2502                    my @lines = $t->cmd("c");
2503                    # Create a snapshot named pb
2504                    @lines = $t->cmd("savevm pb");
2505                    # Write the new status in the VM
2506                    @lines = $t->cmd("commit all");
2507                    # End
2508                    @lines = $t->cmd("quit");
2509                }
2510            }
2511        }
2512        my $hoption = "-p";
2513        my $hpath = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-halt"));
2514        # Solaris doesn't support -p of halt
2515        if ($pbos->{'type'} eq "pkg") {
2516            $hoption = "" ;
2517        }
2518        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)");
2519    }
2520    if (($cmt =~ /^VE/) && ($snapme != 0)) {
2521        my $tpdir = "$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}";
2522        pb_system("sudo tar cz -C $tpdir -f $vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz .","Creating a snapshot of $tpdir");
2523    }
2524}
2525
2526sub pb_script2v {
2527    my $pbscript=shift;
2528    my $vtype=shift;
2529    my $pbforce=shift || 0; # Force stop of VM. Default not.
2530    my $vm1=shift || undef; # Only that VM/VE/RM to treat. Default all.
2531    my $snapme=shift || 0;  # Do we have to create a snapshot. Default not.
2532    my $vm;
2533    my $all;
2534
2535    pb_log(2,"DEBUG: pb_script2v($pbscript,$vtype,$pbforce,".Dumper($vm1).",$snapme)\n");
2536    # Prepare the script to be executed on the VM/VE/RM
2537    # in $ENV{'PBDESTDIR'}/pbscript.$$
2538    if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript.$$")) {
2539        copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript.$$ from $pbscript";
2540        chmod 0755,"$ENV{'PBDESTDIR'}/pbscript.$$";
2541    }
2542
2543    if (not defined $vm1) {
2544        ($vm,$all) = pb_get2v($vtype);
2545    } else {
2546        @$vm = ($vm1);
2547    }
2548    my ($vmexist,$vmpid) = (undef,undef);
2549
2550    foreach my $v (@$vm) {
2551        # Launch VM/VE
2552        ($vmexist,$vmpid) = pb_launchv($vtype,$v,0,$snapme,$pbsnap);
2553
2554        if ($vtype eq "vm") {
2555            pb_log(2,"DEBUG: After pb_launchv, vmexist: $vmexist, vmpid: $vmpid\n");
2556
2557            # Skip that VM/RM if something went wrong
2558            next if (($vmpid == 0) && ($vmexist == 0));
2559
2560            # If force stopping the VM then reset vmexist
2561            if ($pbforce == 1) {
2562                $vmpid = $vmexist;
2563                $vmexist = 0;
2564            }
2565        } else {
2566            #VE
2567            $vmexist = 0;
2568            $vmpid = 0;
2569        }
2570
2571        # Gather all required files to send them to the VM/VE/RM
2572        # and launch the build through pbscript
2573        pb_log(2,"DEBUG: Before send2target, vmexist: $vmexist, vmpid: $vmpid\n");
2574        pb_send2target(uc($vtype)."Script","$v",$vmexist,$vmpid,$snapme);
2575
2576    }
2577}
2578
2579sub pb_launchv {
2580    my $vtype = shift;
2581    my $v = shift;
2582    my $create = shift || 0;        # By default do not create a VM/VE/RM
2583    my $snapme = shift || 0;        # By default do not snap a VM/VE/RM
2584    my $usesnap = shift || 1;       # By default study the usage of the snapshot feature of VM/VE/RM   
2585
2586    # If creation or snapshot creation mode, no snapshot usable
2587    if (($create == 1) || ($snapme == 1)) {
2588        $usesnap = 0;
2589    }
2590
2591    pb_log(2,"DEBUG: pb_launchv($vtype,$v,$create,$snapme,$usesnap)\n");
2592    die "No VM/VE/RM defined, unable to launch" if (not defined $v);
2593    # Keep only the first VM in case many were given
2594    if ($v =~ /,/) {
2595        pb_log(0,"WARNING: pruning to just the first of several VM/VE/RMs listed ($v)\n");
2596        $v =~ s/,.*//;
2597    }
2598
2599    my $pbos = pb_distro_get_context($v);
2600   
2601    pb_apply_conf_proxy($pbos);
2602
2603    # Launch the VMs/VEs
2604    if ($vtype eq "vm") {
2605        die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0));
2606
2607        my ($ptr,$ptr2,$vmpath,$vmport,$vms) = pb_conf_get("vmtype","vmcmd","vmpath","vmport","vmsize");
2608        my ($vmopt,$vmmm,$vmtmout,$vmsnap,$vmbuildtm,$vmmonport) = pb_conf_get_if("vmopt","vmmem","vmtmout","vmsnap","vmbuildtm","vmmonport");
2609        my $vmsize = pb_distro_get_param($pbos,$vms);
2610
2611        my $vmtype = $ptr->{$ENV{'PBPROJ'}};
2612        my $vmcmd = $ptr2->{$ENV{'PBPROJ'}};
2613
2614        if (defined $opts{'g'}) {
2615            if (($vmtype eq "kvm") || ($vmtype eq "qemu")) {
2616                $ENV{'PBVMOPT'} = "--nographic";
2617            }
2618        }
2619        if (not defined $ENV{'PBVMOPT'}) {
2620            $ENV{'PBVMOPT'} = "";
2621        }
2622        # Save the current status for later restoration
2623        $ENV{'PBOLDVMOPT'} = $ENV{'PBVMOPT'};
2624        # Set a default timeout of 2 minutes
2625        if (not defined $ENV{'PBVMTMOUT'}) {
2626            $ENV{'PBVMTMOUT'} = "120";
2627        }
2628        if (defined $vmopt->{$v}) {
2629            $ENV{'PBVMOPT'} .= " $vmopt->{$v}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$v}/);
2630        } elsif (defined $vmopt->{$ENV{'PBPROJ'}}) {
2631            $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/);
2632        }
2633
2634        # How much memory to allocate for VMs
2635        if (defined $vmmm) {
2636            my $vmmem = pb_distro_get_param($pbos,$vmmm);
2637            if (defined $vmmem) {
2638                $ENV{'PBVMOPT'} .= " -m $vmmem";
2639            }
2640        }
2641
2642        # Are we allowed to use snapshot feature
2643        if ($usesnap == 1) {
2644            if ((defined $vmsnap->{$v}) && ($vmsnap->{$v} =~ /true/i)) {
2645                $ENV{'PBVMOPT'} .= " -snapshot";
2646            } elsif ((defined $vmsnap->{$ENV{'PBPROJ'}}) && ($vmsnap->{$ENV{'PBPROJ'}} =~ /true/i)) {
2647                $ENV{'PBVMOPT'} .= " -snapshot";
2648            } elsif ($pbsnap eq 1) {
2649                $ENV{'PBVMOPT'} .= " -snapshot";
2650            }
2651        } 
2652        if ($snapme != 0) {
2653            if (($vmtype eq "kvm") || ($vmtype eq "qemu")) {
2654                # Configure the monitoring to automate the creation of the 'pb' snapshot
2655                $ENV{'PBVMOPT'} .= " -serial mon:telnet::$vmmonport->{$ENV{'PBPROJ'}},server,nowait" if ((defined $vmmonport) && (defined $vmmonport->{$ENV{'PBPROJ'}}));
2656                # In that case no snapshot call needed
2657                $ENV{'PBVMOPT'} =~ s/ -snapshot//;
2658            }
2659        }
2660        if (defined $vmtmout->{$v}) {
2661            $ENV{'PBVMTMOUT'} = $vmtmout->{$v};
2662        } elsif (defined $vmtmout->{$ENV{'PBPROJ'}}) {
2663            $ENV{'PBVMTMOUT'} = $vmtmout->{$ENV{'PBPROJ'}};
2664        }
2665        my $nport = pb_get_port($vmport,$pbos,$vtype);
2666   
2667        my $cmd;
2668        my $vmm;        # has to be used for pb_check_ps
2669        if (($vmtype eq "qemu") || ($vmtype eq "kvm")) {
2670            $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu";
2671            if (($create != 0) || (defined $iso)) {
2672                $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d";
2673            }
2674            # Always redirect the network and always try to use a 'pb' snapshot
2675            #$cmd = "$vmcmd $ENV{'PBVMOPT'} -net nic,model=virtio -net user,hostfwd=tcp::$nport-:22 -loadvm pb $vmm"
2676            $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm"
2677        } elsif ($vmtype eq "xen") {
2678        } elsif ($vmtype eq "vmware") {
2679        } else {
2680            die "VM of type $vmtype not supported. Report to the dev team";
2681        }
2682        # Restore the ENV VAR Value
2683        $ENV{'PBVMOPT'} = $ENV{'PBOLDVMOPT'};
2684
2685        my ($tmpcmd,$void) = split(/ +/,$cmd);
2686        my ($vmexist,$vmmport) = pb_check_ps($tmpcmd,$vmm);
2687        my $vmpid = 0;
2688        if (! $vmexist) {
2689            if ($create != 0) {
2690                die("Found an existing Virtual machine $vmm. Won't overwrite") if (-r $vmm);
2691                if (($vmtype eq "qemu") || ($vmtype eq "xen") || ($vmtype eq "kvm")) {
2692                    my $command = pb_check_req("qemu-img",0);
2693                    pb_system("$command create -f qcow2 $vmm $vmsize","Creating the QEMU VM");
2694                } elsif ($vmtype eq "vmware") {
2695                } else {
2696                }
2697            }
2698            if (! -f "$vmm") {
2699                pb_log(0,"Unable to find VM $vmm\n");
2700            } else {
2701                # Is the SSH port free? if not kill the existing process using it after a build timeout period
2702                my $vmssh = pb_check_ps($tmpcmd,"tcp:$nport:10.0.2.15:22");
2703                if ($vmssh) {
2704                    my $buildtm = $ENV{'PBVMTMOUT'};
2705                    if (defined $vmbuildtm->{$v}) {
2706                        $buildtm = $vmbuildtm->{$v};
2707                    } elsif (defined $vmbuildtm->{$ENV{'PBPROJ'}}) {
2708                        $buildtm = $vmbuildtm->{$ENV{'PBPROJ'}};
2709                    }
2710
2711                    sleep $buildtm;
2712                    pb_log(0,"WARNING: Killing the process ($vmssh) using port $nport (previous failed VM ?)\n");
2713                    kill 15,$vmssh;
2714                    # Let it time to exit
2715                    sleep 5;
2716                }
2717                pb_system("$cmd &","Launching the VM $vmm");
2718                # Using system allows to kill it externaly if needed,sosupport that in the call
2719                pb_system("sleep $ENV{'PBVMTMOUT'}","Waiting $ENV{'PBVMTMOUT'} s for VM $v to come up","mayfail");
2720                $vmpid = pb_check_ps($tmpcmd,$vmm);
2721                pb_log(0,"VM $vmm launched (pid $vmpid)\n");
2722            }
2723        } else {
2724            pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n");
2725            # Set the correct port here based on what is done
2726            $pbport = $vmmport;
2727            $vmpid = $vmexist;
2728        }
2729        pb_log(2,"DEBUG: pb_launchv returns ($vmexist,$vmpid)\n");
2730        return($vmexist,$vmpid);
2731    } elsif ($vtype eq "ve") {
2732        # Force the creation of the VE and no snapshot usable
2733        pb_ve_launch($v,$create,$usesnap);
2734    } else {
2735        # RM here
2736        # Get distro context
2737        my $pbos = pb_distro_get_context($v);
2738
2739        # Get RM context
2740        my ($ptr,$rmpath) = pb_conf_get("rmtype","rmpath");
2741
2742        # Nothing more to do for RM. No real launch
2743        # For the moment we support the RM is already running
2744        # For ProLiant may be able to power them on if needed later on as an example.
2745    }
2746}
2747
2748# Return string for date synchro
2749sub pb_date2v {
2750
2751my $vtype = shift;
2752my $pbos = shift;
2753my $nontp = shift || 0;
2754
2755pb_log(1,"Entering pb_date2v\n");
2756# VE gets time from parent OS.
2757return "/bin/true" if ($vtype) =~ /^ve/o; 
2758
2759my ($ntp) = pb_conf_get_if($vtype."ntp");
2760my $vntp = undef;
2761my $ntpline = undef;
2762$vntp = $ntp->{$ENV{'PBPROJ'}} if (defined $ntp);
2763
2764if ((defined $vntp) && ($vntp !~ /^\s*$/)) {
2765    pb_log(2,"ntp server is $vntp\n");
2766    # ntp command depends on pbos
2767    my $vntpcmd = pb_distro_get_param($pbos,pb_conf_get("oscmdntp"));
2768    $ntpline = "sudo $vntpcmd $vntp";
2769}
2770# Force new date to be in the future compared to the date
2771# of the host by adding 1 minute
2772my @date=pb_get_date();
2773$date[1]++;
2774my $upddate = strftime("%m%d%H%M%Y", @date);
2775my $dateline = "sudo /bin/date $upddate";
2776if ((defined $ntpline) && ($nontp == 0)) {
2777    pb_log(1,"pb_date2v returns $ntpline\n");
2778    return($ntpline);
2779} else {
2780    pb_log(1,"pb_date2v returns $dateline\n");
2781    return($dateline);
2782}
2783}
2784
2785sub pb_build2v {
2786
2787my $vtype = shift;
2788my $action = shift || "build";
2789
2790my ($v,$all) = pb_get2v($vtype);
2791
2792# Send tar files when we do a global generation
2793pb_build2ssh() if (($all == 1) && ($action eq "build"));
2794
2795# Adapt // mode to memory size
2796$pbparallel = pb_set_parallel($vtype);
2797
2798my ($vmexist,$vmpid) = (undef,undef);
2799my $pm;
2800my $all_ok = 1;
2801if (defined $pbparallel) {
2802    $pm = new Parallel::ForkManager($pbparallel);
2803
2804    # Set which port the VM/RM will use to communicate
2805    $pm->run_on_start(\&pb_set_port);
2806    $pm->run_on_finish(sub { my ($pid, $code, $id, $signal, $dump) = @_;
2807                            unless ($code == 0 && $signal == 0 && $dump == 0) {
2808                                $all_ok = 0;
2809                                pb_log(0,"ERROR: pid $pid failed\n");
2810                            }
2811                        });
2812}
2813
2814my $counter = 0;
2815foreach my $v (@$v) {
2816    $counter++;
2817    # Modulo 2 * pbparallel (to avoid synchronization problems)
2818    $counter = 1 if ((defined $pbparallel) && ($counter > 2 * $pbparallel));
2819    $pm->start($counter) and next if (defined $pbparallel);
2820    # Prepare the script to be executed on the VM/VE/RM
2821    # in $ENV{'PBDESTDIR'}/pbscript.$$
2822    open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript.$$") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript.$$";
2823    print SCRIPT "#!/bin/bash\n";
2824
2825    # Transmit the verbosity level to the virtual env/mach.
2826    my $verbose = "";
2827    my $i = 0;                          # minimal debug level
2828    while ($i lt $pbdebug) {
2829        $verbose .= "-v ";
2830        $i++;
2831    }
2832    print SCRIPT "set -e\n" if ($Global::pb_stop_on_error);
2833    # Activate script verbosity if at least 2 for pbdebug
2834    print SCRIPT "set -x\n" if ($i gt 1);
2835    # Quiet if asked to be so on the original system
2836    $verbose = "-q" if ($pbdebug eq -1);
2837
2838    print SCRIPT "echo ... Execution needed\n";
2839    print SCRIPT "echo ==== Start of script $$ for $vtype $v =====\n";
2840    print SCRIPT "# This is in directory delivery\n";
2841    print SCRIPT "# Setup the variables required for building\n";
2842    print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n";
2843
2844    if ($action eq "build") {
2845        print SCRIPT "# Preparation for pb\n";
2846        print SCRIPT "rm -f \$HOME/.pbrc\n";
2847        print SCRIPT "mv .pbrc \$HOME\n";
2848        print SCRIPT "cd ..\n";
2849    }
2850
2851    # VE needs a good /proc, tolerate one being potentially left around after a failure
2852    if ($vtype eq "ve") {
2853        print SCRIPT "[ -d /proc/1 ] || sudo /bin/mount -t proc /proc /proc\n";
2854    }
2855
2856    # Get distro context
2857    my $pbos = pb_distro_get_context($v);
2858   
2859    my $ntpline = pb_date2v($vtype,$pbos);
2860    print SCRIPT "# Time sync\n";
2861    print SCRIPT "echo setting up date with $ntpline\n";
2862    print SCRIPT "$ntpline\n";
2863    print SCRIPT "if [ \$\? -ne 0 ]; then\n";
2864    # Force if bad status a trick using date
2865    $ntpline = pb_date2v($vtype,$pbos, 1);
2866    print SCRIPT "  $ntpline\n";
2867    print SCRIPT "fi\n";
2868    # Use potential local proxy declaration in case we need it to download repo, pkgs, ...
2869    if (defined $ENV{'http_proxy'}) {
2870        print SCRIPT "export http_proxy=\"$ENV{'http_proxy'}\"\n";
2871    }
2872
2873    if (defined $ENV{'ftp_proxy'}) {
2874        print SCRIPT "export ftp_proxy=\"$ENV{'ftp_proxy'}\"\n";
2875    }
2876
2877    # Get list of packages to build/test and get some ENV vars as well
2878    my $ptr = pb_get_pkg();
2879    @pkgs = @$ptr;
2880    my $p = join(' ',@pkgs) if (@pkgs);
2881    print SCRIPT "export PBPROJVER=$ENV{'PBPROJVER'}\n";
2882    print SCRIPT "export PBPROJTAG=$ENV{'PBPROJTAG'}\n";
2883    print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n";
2884
2885    # We may need to do some other tasks before building. Read a script here to finish setup
2886    if (-x "$ENV{'PBDESTDIR'}/pb$vtype".".pre") {
2887        print SCRIPT "# Special pre-instructions to be launched\n";
2888        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype".".pre");
2889    }
2890
2891    if (-x "$ENV{'PBDESTDIR'}/pb$vtype"."$action.pre") {
2892        print SCRIPT "# Special pre-$action instructions to be launched\n";
2893        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype"."$action.pre");
2894    }
2895
2896    print SCRIPT "# $action\n";
2897    print SCRIPT "echo $action"."ing packages on $vtype...\n";
2898
2899    if (($action eq "test") && (! -x "$ENV{'PBDESTDIR'}/pbtest")) {
2900            die "No test script ($ENV{'PBDESTDIR'}/pbtest) found when in test mode. Aborting ...";
2901    }
2902    print SCRIPT "pb $verbose -p $ENV{'PBPROJ'} $action"."2pkg $p\n";
2903
2904    if ($vtype eq "ve") {
2905        print SCRIPT "sudo /bin/umount /proc\n";
2906    }
2907
2908    # We may need to do some other tasks after building. Read a script here to exit properly
2909    if (-x "$ENV{'PBDESTDIR'}/pb$vtype"."$action.post") {
2910        print SCRIPT "# Special post-$action instructions to be launched\n";
2911        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype"."$action.post");
2912    }
2913
2914    if (-x "$ENV{'PBDESTDIR'}/pb$vtype".".post") {
2915        print SCRIPT "# Special post-instructions to be launched\n";
2916        print SCRIPT pb_get_content("$ENV{'PBDESTDIR'}/pb$vtype".".post");
2917    }
2918
2919    print SCRIPT "echo ==== End of script $$ for $vtype $v =====\n";
2920    close(SCRIPT);
2921    chmod 0755,"$ENV{'PBDESTDIR'}/pbscript.$$";
2922   
2923    # Launch the VM/VE/RM
2924    ($vmexist,$vmpid) = pb_launchv($vtype,$v,0);
2925
2926
2927    if ($vtype eq "vm") {
2928        # Skip that VM if something went wrong
2929        if (($vmpid == 0) && ($vmexist == 0)) {
2930            $pm->finish if (defined $pbparallel);
2931            next;
2932        }
2933    } else {
2934        # VE/RM
2935        $vmexist = 0;
2936        $vmpid = 0;
2937    }
2938    # Gather all required files to send them to the VM/VE
2939    # and launch the build through pbscript
2940    pb_log(2,"Calling send2target $vtype,$v,$vmexist,$vmpid\n");
2941    pb_send2target(uc($vtype).$action,"$v",$vmexist,$vmpid);
2942    $pm->finish if (defined $pbparallel);
2943}
2944$pm->wait_all_children if (defined $pbparallel);
2945die "Aborting, one or more of the children failed." if ((not $all_ok) && ($Global::pb_stop_on_error));
2946}
2947
2948
2949sub pb_clean {
2950
2951    my $sleep=10;
2952    die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'});
2953    die "Unable to get env var PBBUILDDIR" if (not defined $ENV{'PBBUILDDIR'});
2954    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");
2955    sleep $sleep;
2956    pb_rm_rf($ENV{'PBDESTDIR'});
2957    pb_rm_rf($ENV{'PBBUILDDIR'});
2958}
2959
2960sub pb_newver {
2961
2962    die "-V Version parameter needed" if ((not defined $newver) || ($newver eq ""));
2963
2964    # Need this call for PBDIR
2965    my ($scheme2,$uri) = pb_cms_init($pbinit);
2966
2967    my ($pbconf,$pburl) = pb_conf_get("pbconfurl","pburl");
2968    $uri = $pbconf->{$ENV{'PBPROJ'}};
2969    my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
2970
2971    # Checking CMS repositories status
2972    ($scheme2, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}});
2973
2974    if ($scheme !~ /^svn/) {
2975        die "Only SVN is supported at the moment";
2976    }
2977
2978    my $res = pb_vcs_isdiff($scheme,$ENV{'PBROOTDIR'});
2979    die "ERROR: No differences accepted in CMS for $ENV{'PBROOTDIR'} before creating a new version" if ($res != 0);
2980
2981    $res = pb_vcs_isdiff($scheme2,$ENV{'PBDIR'});
2982    die "ERROR: No differences accepted in CMS for $ENV{'PBDIR'} before creating a new version" if ($res != 0);
2983
2984    # Tree identical between PBCONFDIR and PBROOTDIR. The delta is what
2985    # we want to get for the root of the new URL
2986
2987    my $oldver = $ENV{'PBROOTDIR'};
2988    $oldver =~ s|^$ENV{'PBCONFDIR'}||;
2989
2990    pb_log(2, "PBCONFDIR: $ENV{'PBCONFDIR'}\nPBROOTDIR: $ENV{'PBROOTDIR'}\n");
2991
2992    my $newurl = "$uri/$newver";
2993    # Should probably use projver in the old file
2994    my $oldvertxt= basename($oldver);
2995    my $newvertxt = basename($newver);
2996
2997    # Duplicate and extract project-builder part
2998    pb_log(2,"Copying $uri/$oldver to $newurl\n");
2999    pb_vcs_copy($scheme,"$uri/$oldver",$newurl);
3000    pb_log(2,"Checkout $newurl to $ENV{'PBCONFDIR'}/$newver\n");
3001    pb_vcs_up($scheme,"$ENV{'PBCONFDIR'}");
3002
3003    # Duplicate and extract project
3004    my $newurl2 = "$pburl->{$ENV{'PBPROJ'}}/$newver";
3005
3006    pb_log(2,"Copying $pburl->{$ENV{'PBPROJ'}}/$oldver to $newurl2\n");
3007    pb_vcs_copy($scheme2,"$pburl->{$ENV{'PBPROJ'}}/$oldver",$newurl2);
3008
3009    my $tmp = $ENV{'PBDIR'};
3010    $tmp =~ s|$oldver$||;
3011    pb_log(2,"Checkout $newurl2 to $tmp/$newver\n");
3012    pb_vcs_up($scheme2,"$tmp");
3013
3014    # Update the .pb file
3015    open(FILE,"$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb";
3016    open(OUT,"> $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new";
3017    while(<FILE>) {
3018        if (/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldvertxt$/) {
3019            s/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldvertxt$/projver $ENV{'PBPROJ'} = $newvertxt/;
3020            pb_log(0,"Changing projver from $oldvertxt to $newvertxt in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n");
3021        }
3022        if (/^testver/) {
3023            s/^testver/#testver/;
3024            pb_log(0,"Commenting testver in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n") if (/^testver/);
3025        }
3026        if (/^delivery/) {
3027            my $txt = $_;
3028            chomp($txt);
3029            pb_log(0,"Please check delivery ($txt) in $ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb\n");
3030        }
3031        print OUT $_;
3032    }
3033    close(FILE);
3034    close(OUT);
3035    rename("$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb.new","$ENV{'PBCONFDIR'}/$newver/$ENV{'PBPROJ'}.pb");
3036
3037    # Checking pbcl files
3038    foreach my $f (<$ENV{'PBROOTDIR'}/*/pbcl>) {
3039        # Compute new pbcl file
3040        my $f2 = $f;
3041        $f2 =~ s|$ENV{'PBROOTDIR'}|$ENV{'PBCONFDIR'}/$newver/|;
3042        open(PBCL,$f) || die "Unable to open $f";
3043        my $foundnew = 0;
3044        while (<PBCL>) {
3045            $foundnew = 1 if (/^$newvertxt \(/);
3046        }
3047        close(PBCL);
3048        open(OUT,"> $f2") || die "Unable to write to $f2: $!";
3049        open(PBCL,$f) || die "Unable to open $f";
3050        # We skip as long as we do not reach the new version in the log (case of devel)
3051        my $skip = 1;
3052        # We let the 4 first lines
3053        my $cnt = 0;
3054        while (<PBCL>) {
3055            $skip = 0 if (/^$newvertxt \(/);
3056            if ((/^$oldvertxt \(/) && ($foundnew == 0)) {
3057                print OUT "$newvertxt ($pbdate)\n";
3058                print OUT "- TBD\n";
3059                print OUT "\n";
3060                pb_log(0,"WARNING: version $newvertxt not found in $f so added to $f2...\n") if ($foundnew == 0);
3061            }
3062            if ($cnt <= 4) {
3063                print OUT "$_" if (not /^$oldvertxt \(/);
3064            } else {
3065                print OUT "$_" if ($skip == 0);
3066            }
3067            $cnt++;
3068        }
3069        close(OUT);
3070        close(PBCL);
3071    }
3072
3073    pb_log(2,"Checkin $ENV{'PBCONFDIR'}/$newver\n");
3074    pb_cms_checkin($scheme,"$ENV{'PBCONFDIR'}/$newver",undef);
3075}
3076
3077#
3078# Return the list of VMs/VEs/RMs we are working on
3079# $all is a flag to know if we return all of them
3080# or only some (if all we publish also tar files in addition to pkgs
3081#
3082sub pb_get2v {
3083
3084my $vtype = shift;
3085my @v;
3086my $all = 0;
3087my $pbv = 'PBV';
3088my $vlist = $vtype."list";
3089
3090# Get VM/VE list
3091if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) {
3092    my ($ptr) = pb_conf_get($vlist);
3093    $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}};
3094    $all = 1;
3095}
3096pb_log(2,"$vtype: $ENV{$pbv}\n");
3097@v = split(/,/,$ENV{$pbv});
3098return(\@v,$all);
3099}
3100
3101# This function creates a giant script to configure a particular VM/VE/RM, it then copies the
3102# script to the target.
3103
3104# Function to create a potentialy missing pb account on the VM/VE/RM, and adds it to sudo
3105# Needs to use root account to connect to the VM/VE/RM
3106# pb will take your local public SSH key to access
3107# the pb account in the VM/VE/RM later on if needed
3108sub pb_setup2v {
3109
3110my $vtype = shift;
3111my $sbx = shift || undef;
3112
3113my ($vm,$all) = pb_get2v($vtype);
3114
3115# Script generated
3116my $pbscript = "$ENV{'PBDESTDIR'}/setupv.$$";
3117
3118# Adapt // mode to memory size
3119$pbparallel = pb_set_parallel($vtype);
3120
3121my $pm;
3122my $all_ok = 1;
3123if (defined $pbparallel) {
3124    $pm = new Parallel::ForkManager($pbparallel);
3125
3126    # Set which port the VM/RM will use to communicate
3127    $pm->run_on_start(\&pb_set_port);
3128    $pm->run_on_finish(sub { my ($pid, $code, $id, $signal, $dump) = @_;
3129                            $all_ok = 0 unless (($code == 0) && ($signal == 0) && ($dump == 0)); 
3130                        });
3131}
3132
3133my $counter = 0;
3134foreach my $v (@$vm) {
3135    $counter++;
3136    # Modulo pbparallel
3137    $counter = 1 if ((defined $pbparallel) && ($counter > $pbparallel));
3138    $pm->start($counter) and next if (defined $pbparallel);
3139
3140    # Get distro context
3141    my $pbos = pb_distro_get_context($v);
3142   
3143    # Deal with date sync.
3144    my $ntpline = pb_date2v($vtype,$pbos);
3145
3146    # Name of the account to deal with for VM/VE/RM
3147    # Do not use the one passed potentially with -a
3148    my ($pbac) = pb_conf_get($vtype."login");
3149    my ($key,$zero0,$zero1,$zero2);
3150    my ($vmexist,$vmpid);
3151
3152    # Prepare the script to be executed on the VM/VE/RM
3153    # in $ENV{'PBDESTDIR'}/setupv
3154    open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
3155   
3156    print SCRIPT << 'EOF';
3157#!/usr/bin/perl -w
3158
3159use strict;
3160use File::Copy;
3161
3162# We should not need in this script more functions than what is provided
3163# by Base, Conf and Distribution to avoid problems at exec time.
3164# They are appended at the end.
3165
3166# Define mandatory global vars
3167EOF
3168    my $ppref = "our";
3169    $ppref = "my" if (($pbos->{'name'} =~ /^redhat/) && ($pbos->{'version'} =~ /^6/));
3170    print SCRIPT << "EOF";
3171$ppref \$pbdebug = $pbdebug;
3172$ppref \$pbLOG;
3173$ppref \$pbsynmsg = "pbscript";
3174$ppref \$pbdisplaytype = "text";
3175$ppref \$pblocale = "";
3176EOF
3177    print SCRIPT << 'EOF';
3178pb_log_init($pbdebug, $pbLOG);
3179EOF
3180    print SCRIPT << "EOF";
3181\$Global::pb_stop_on_error = $Global::pb_stop_on_error;
3182pb_temp_init($pbkeep);
3183pb_conf_init("$ENV{'PBPROJ'}");
3184
3185EOF
3186
3187    # Launch the VM/VE/RM - Usage of snapshot disabled
3188    ($vmexist,$vmpid) = pb_launchv($vtype,$v,0,0,0);
3189
3190    my $keyfile;
3191    my $nport;
3192    my $vmhost;
3193
3194    # Prepare the key to be used and transfered remotely
3195    $keyfile = pb_ssh_get(1);
3196       
3197    if ($vtype =~ /(v|r)m/) {
3198        my ($vmport);
3199        ($vmhost,$vmport) = pb_conf_get($vtype."host",$vtype."port");
3200        $nport = pb_get_port($vmport,$pbos,$vtype);
3201   
3202        # Skip that VM/RM if something went wrong
3203        next if (($vmpid == 0) && ($vmexist == 0));
3204   
3205        # Store the pub key part in a variable
3206        open(FILE,"$keyfile.pub") || die "Unable to open $keyfile.pub";
3207        ($zero0,$zero1,$zero2) = split(/ /,<FILE>);
3208        close(FILE);
3209
3210        $key = "\Q$zero1";
3211
3212        # We call true to avoid problems if SELinux is not activated, but chcon is present and returns in that case 1
3213        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");
3214        # once this is done, we can do what we need on the VM/RM remotely
3215    } elsif ($vtype eq "ve") {
3216        print SCRIPT << "EOF";
3217# For VE we first need to mount some FS
3218pb_system("mount -t proc /proc /proc") unless (-d "/proc/$$");
3219
3220# For VE we need a good null dev
3221# Except for RedHat 6.2 where it's good and doesnt like being recreated
3222EOF
3223        print SCRIPT "pb_system('rm -f /dev/null; mknod /dev/null c 1 3; chmod 777 /dev/null');\n" unless (($pbos->{'name'} =~ /^redhat/) && ($pbos->{'version'} =~ /^6/));
3224    } else {
3225        die "Unknown virtual type $vtype";
3226    }
3227
3228    if ($vtype =~ /(v|r)m/) {
3229        print SCRIPT << 'EOF';
3230# Removes duplicate in .ssh/authorized_keys of our key if needed
3231#
3232my $file1="$ENV{'HOME'}/.ssh/authorized_keys";
3233open(PBFILE,$file1) || die "Unable to open $file1";
3234open(PBOUT,"> $file1.new") || die "Unable to open $file1.new";
3235my $count = 0;
3236while (<PBFILE>) {
3237
3238EOF
3239        print SCRIPT << "EOF";
3240    if (/ $key /) {
3241        \$count++;
3242    }
3243print PBOUT \$_ if ((\$count <= 1) || (\$_ !~ / $key /));
3244}
3245close(PBFILE);
3246close(PBOUT);
3247rename("\$file1.new",\$file1);
3248chmod 0600,\$file1;
3249
3250EOF
3251    }
3252    print SCRIPT << 'EOF';
3253
3254# Adds $pbac->{$ENV{'PBPROJ'}} as an account if needed
3255#
3256my $file="/etc/passwd";
3257open(PBFILE,$file) || die "Unable to open $file";
3258my $found = 0;
3259while (<PBFILE>) {
3260EOF
3261    print SCRIPT << "EOF";
3262    \$found = 1 if (/^$pbac->{$ENV{'PBPROJ'}}:/);
3263EOF
3264
3265# TODO: use an external parameter
3266my $home = "/home";
3267# Solaris doesn't like that we use /home
3268$home = "/export/home" if ($pbos->{'type'} eq "pkg");
3269
3270    print SCRIPT << "EOF";
3271}
3272close(PBFILE);
3273
3274if ( \$found == 0 ) {
3275    if ( ! -d "$home" ) {
3276        pb_mkdir_p("$home");
3277    }
3278EOF
3279    # TODO: Level of portability of these cmds ? Critical now for RM
3280    # TODO: Check existence before adding to avoid errors
3281    print SCRIPT << "EOF";
3282pb_system("/usr/sbin/groupadd $pbac->{$ENV{'PBPROJ'}}","Adding group $pbac->{$ENV{'PBPROJ'}}");
3283pb_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'}})");
3284}
3285EOF
3286
3287    # Copy the content of our local conf file to the VM/VE/RM
3288    my $content = pb_get_content(pb_distro_conffile());
3289    print SCRIPT << "EOF";
3290    #
3291    # Create a temporary local conf file for distribution support
3292    # This is created here before its use later. Its place is hardcoded, so no choice for the path
3293    #
3294    my \$tempconf = pb_distro_conffile();
3295    pb_mkdir_p(dirname(\$tempconf));
3296    open(CONF,"> \$tempconf") || die "Unable to create \$tempconf";
3297    print CONF q{$content};
3298    close(CONF);
3299EOF
3300
3301    if ($vtype =~ /(v|r)m/) {
3302        print SCRIPT << "EOF";
3303# allow ssh entry to build
3304#
3305mkdir "$home/$pbac->{$ENV{'PBPROJ'}}/.ssh",0700;
3306# Allow those accessing root to access the build account
3307copy("\$ENV{'HOME'}/.ssh/authorized_keys","$home/$pbac->{$ENV{'PBPROJ'}}/.ssh/authorized_keys");
3308chmod 0600,".ssh/authorized_keys";
3309pb_system("chown -R $pbac->{$ENV{'PBPROJ'}}:$pbac->{$ENV{'PBPROJ'}} $home/$pbac->{$ENV{'PBPROJ'}}","Finish setting up the account env for $pbac->{$ENV{'PBPROJ'}}");
3310
3311EOF
3312}
3313    print SCRIPT << 'EOF';
3314# No passwd for build account only keys
3315$file="/etc/shadow";
3316if (-f $file) {
3317    open(PBFILE,$file) || die "Unable to open $file";
3318    open(PBOUT,"> $file.new") || die "Unable to open $file.new";
3319    while (<PBFILE>) {
3320EOF
3321    print SCRIPT << "EOF";
3322        s/^$pbac->{$ENV{'PBPROJ'}}:\!\!:/$pbac->{$ENV{'PBPROJ'}}:*:/;
3323        s/^$pbac->{$ENV{'PBPROJ'}}:\!:/$pbac->{$ENV{'PBPROJ'}}:*:/; #SLES 9 e.g.
3324        s/^$pbac->{$ENV{'PBPROJ'}}:\\*LK\\*:/$pbac->{$ENV{'PBPROJ'}}:NP:/;  #Solaris e.g.
3325EOF
3326        print SCRIPT << 'EOF';
3327        print PBOUT $_;
3328    }
3329    close(PBFILE);
3330    close(PBOUT);
3331    rename("$file.new",$file);
3332    chmod 0640,$file;
3333    }
3334
3335# Keep the VM in text mode
3336$file="/etc/inittab";
3337if (-f $file) {
3338    open(PBFILE,$file) || die "Unable to open $file";
3339    open(PBOUT,"> $file.new") || die "Unable to open $file.new";
3340    while (<PBFILE>) {
3341        s/^(..):5:initdefault:$/$1:3:initdefault:/;
3342        print PBOUT $_;
3343    }
3344    close(PBFILE);
3345    close(PBOUT);
3346    rename("$file.new",$file);
3347    chmod 0640,$file;
3348}
3349
3350# pb has to be added to portage group on gentoo
3351
3352# We need to have that pb_distro_get_context function
3353# Get it from Project-Builder::Distribution
3354# And we now need the conf file required for this to work created above
3355
3356my $pbos = pb_distro_get_context(); 
3357print "distro tuple: ".Dumper($pbos)."\n";
3358
3359# Adapt sudoers
3360# sudo is not default on Solaris and needs to be installed first
3361# from http://www.sunfreeware.com/programlistsparc10.html#sudo
3362if ($pbos->{'type'} eq "pkg") {
3363    $file="/usr/local/etc/sudoers";
3364} else {
3365    $file="/etc/sudoers";
3366}
3367open(PBFILE,$file) || die "Unable to open $file";
3368open(PBOUT,"> $file.new") || die "Unable to open $file.new";
3369while (<PBFILE>) {
3370EOF
3371    # Skip what will be generated
3372    print SCRIPT << "EOF";
3373    next if (/^$pbac->{$ENV{'PBPROJ'}}\\s+/);
3374    next if (/^Defaults:$pbac->{$ENV{'PBPROJ'}}\\s+/);
3375    next if (/^Defaults:root\\s+\!requiretty/);
3376    next if (/^Defaults:root\\s+env_keep/);
3377EOF
3378    print SCRIPT << 'EOF';
3379    s/Defaults\s+requiretty/# disable Defaults: requiretty/;
3380    print PBOUT $_;
3381}
3382close(PBFILE);
3383EOF
3384    print SCRIPT << "EOF";
3385# Some distro force requiretty at compile time, so disable here
3386print PBOUT "Defaults:$pbac->{$ENV{'PBPROJ'}} !requiretty\n";
3387print PBOUT "Defaults:root !requiretty\n";
3388EOF
3389    # RH 6.2 sudo doesn't support env_keep
3390    if (($pbos->{'name'} ne "redhat") && ($pbos->{'version'} ne "6.2")) {
3391        print SCRIPT << "EOF";
3392# Keep proxy configuration while using sudo
3393print PBOUT "Defaults:$pbac->{$ENV{'PBPROJ'}}    env_keep += \\\"http_proxy ftp_proxy\\\"\n";
3394print PBOUT "Defaults:root    env_keep += \\\"http_proxy ftp_proxy\\\"\n";
3395EOF
3396    }
3397    # Try to restrict security to what is really needed
3398    if ($vtype =~ /^vm/) {
3399        my $hpath = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-halt"));
3400        my @sudocmds = pb_get_sudocmds($pbos,$ntpline,"sudo $hpath","sudo /bin/date");
3401        print SCRIPT << "EOF";
3402# This is needed in order to be able on VM to halt the machine from the $pbac->{$ENV{'PBPROJ'}} account at least
3403# Build account $pbac->{$ENV{'PBPROJ'}} in VM also needs to setup date and install deps.
3404# Nothing else should be needed
3405EOF
3406        foreach my $c (@sudocmds) {
3407            print SCRIPT "print PBOUT \"$pbac->{$ENV{'PBPROJ'}}   ALL = NOPASSWD: $c\\n\";\n";
3408        }
3409    } elsif ($vtype =~ /^rm/) {
3410        my @sudocmds = pb_get_sudocmds($pbos,$ntpline);
3411        print SCRIPT << "EOF";
3412# Build account $pbac->{$ENV{'PBPROJ'}} in RM only needs to setup date and install deps if needed each time
3413EOF
3414        foreach my $c (@sudocmds) {
3415            print SCRIPT "print PBOUT \"$pbac->{$ENV{'PBPROJ'}}   ALL = NOPASSWD: $c\\n\";\n";
3416        }
3417    } else {
3418        print SCRIPT << "EOF";
3419# Build account $pbac->{$ENV{'PBPROJ'}} for VE needs to do a lot in the host (and chroot), so allow without restriction for now
3420print PBOUT "$pbac->{$ENV{'PBPROJ'}}   ALL=(ALL) NOPASSWD:ALL\n";
3421EOF
3422    }
3423    my $sudomode = pb_distro_get_param($pbos,pb_conf_get("ossudoersmode"));
3424    print SCRIPT << 'EOF';
3425close(PBOUT);
3426rename("$file.new",$file);
3427EOF
3428    print SCRIPT << "EOF";
3429chmod 0$sudomode,\$file;
3430
3431EOF
3432
3433    if ($vtype =~ /(v|r)m/) {
3434        # Sync date
3435        # do it after sudoers is setup
3436        print SCRIPT "my \$res = pb_system(\"$ntpline\",\"Updating time with $ntpline\",\"mayfailverbose\");\n";
3437        print SCRIPT "if (\$res != 0) {\n";
3438        # try again with another method
3439        $ntpline = pb_date2v($vtype,$pbos,1);
3440        print SCRIPT "  pb_system(\"$ntpline\",\"Updating time with $ntpline\",\"mayfailverbose\");\n";
3441        print SCRIPT "}\n";
3442    }
3443
3444    print SCRIPT << 'EOF';
3445   
3446# We may need a proxy configuration. Get it from the local env
3447pb_apply_conf_proxy($pbos);
3448
3449# First install all required packages
3450pb_system("yum clean all","Cleaning yum env","mayfail") if (($pbos->{'name'} eq "fedora") || ($pbos->{'name'} eq "asianux") || ($pbos->{'name'} eq "rhel"));
3451my ($ospkgdep) = pb_conf_get_if("ospkgdep");
3452   
3453my $pkgdep = pb_distro_get_param($pbos,$ospkgdep);
3454pb_distro_installdeps(undef,$pbos,pb_distro_only_deps_needed($pbos,join(' ',split(/,/,$pkgdep))));
3455
3456EOF
3457    my $itype = pb_distro_get_param($pbos,pb_conf_get("pbinstalltype"));
3458    # Install from sandbox mean a file base install
3459    $itype = "file" if (defined $sbx);
3460    if ($itype =~ /^file/) {
3461        my $cmdget;
3462        if (defined $sbx) {
3463            # Install from sandbox mean using the result of the just passed sbx2build command
3464            # Get content saved in cms2build
3465            my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
3466            my $pbextdir = pb_get_extdir();
3467            die "Unable to get package list" if (not defined $pkg);
3468
3469            # We consider 2 specific packages
3470            my $vertag1 = $pkg->{"ProjectBuilder"};
3471            my $vertag2 = $pkg->{"project-builder"};
3472            # get the version of the current package - maybe different
3473            pb_log(2,"Vertag1: $vertag1\n");
3474            pb_log(2,"Vertag2: $vertag2\n");
3475            my ($pbver1,$tmp1) = split(/-/,$vertag1);
3476            my ($pbver2,$tmp2) = split(/-/,$vertag2);
3477            # Copy inside the VE
3478            if ($vtype eq "ve") {
3479                my ($vepath) = pb_conf_get("vepath");
3480                copy("$ENV{'PBDESTDIR'}/ProjectBuilder-$pbver1$pbextdir.tar.gz","$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/tmp");
3481                copy("$ENV{'PBDESTDIR'}/project-builder-$pbver2$pbextdir.tar.gz","$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/tmp");
3482            } else {
3483                pb_system("scp -i $keyfile -p -o UserKnownHostsFile=/dev/null -P $nport $ENV{'PBDESTDIR'}/ProjectBuilder-$pbver1$pbextdir.tar.gz $ENV{'PBDESTDIR'}/project-builder-$pbver2$pbextdir.tar.gz root\@$vmhost->{$ENV{'PBPROJ'}}:/tmp","Copying local project files to $vtype.");
3484            }
3485            $cmdget = "mv /tmp/ProjectBuilder-$pbver1$pbextdir.tar.gz ProjectBuilder-latest.tar.gz ; mv /tmp/project-builder-$pbver2$pbextdir.tar.gz project-builder-latest.tar.gz";
3486        } else {
3487            # TODO: shouldn't we have a variable to specify the source file?
3488            # And shouldn't we be getting the one that matches the current pb version?
3489            # For the moment, just take the latest stable one
3490            $cmdget = "wget --passive-ftp ftp://ftp.project-builder.org/src/ProjectBuilder-latest.tar.gz; wget --passive-ftp ftp://ftp.project-builder.org/src/project-builder-latest.tar.gz";
3491        }
3492        print SCRIPT << 'EOF';
3493# Then install manually the missing perl modules
3494my ($osperldep,$osperlver) = pb_conf_get_if("osperldep","osperlver");
3495   
3496my $perldep = pb_distro_get_param($pbos,$osperldep);
3497my $bashopt = "";
3498$bashopt = "-x" if ($pbdebug ge 1);
3499my $verbopt = "mayfail";
3500$verbopt = "mayfailverbose" if ($pbdebug ge 1);
3501foreach my $m (split(/,/,$perldep)) {
3502    # Skip empty deps
3503    next if ($m =~ /^\s*$/);
3504    my $dir = $m;
3505    $dir =~ s/-.*//;
3506    pb_system("echo \"rm -rf $m* ; wget http://search.cpan.org/CPAN/modules/by-module/$dir/$m-$osperlver->{$m}.tar.gz ; gzip -cd $m-$osperlver->{$m}.tar.gz | tar xf - ; cd $m* ; if [ -f Build.PL ]; then perl Build.PL; ./Build ; ./Build install ; else perl Makefile.PL; make ; make install ; fi; cd .. ; rm -rf $m*\" | bash -e $bashopt" ,"Installing perl module $m-$osperlver->{$m}",$verbopt);
3507}
3508EOF
3509        print SCRIPT << 'EOF';
3510pb_system("rm -rf ProjectBuilder-* ; rm -rf project-builder-* ; rm -rf `perl -V:installvendorlib  | awk -F\"'\" '{print \$2}'`/ProjectBuilder ;
3511EOF
3512        print SCRIPT " $cmdget ; ";
3513        print SCRIPT << 'EOF'
3514gzip -cd ProjectBuilder-latest.tar.gz | tar xf - ; cd ProjectBuilder-* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf ProjectBuilder-* ; gzip -cd project-builder-latest.tar.gz | tar xf - ; cd project-builder-* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf project-builder-* ;","Building Project-Builder");
3515EOF
3516    } elsif ($itype =~ /^pkg/) {
3517        # pkg based install. We need to point to the project-builder.org repository
3518        print SCRIPT << 'EOF';
3519my $pkgforpb = pb_distro_get_param($pbos,pb_conf_get_if("ospkg"));
3520pb_distro_setuposrepo($pbos);
3521pb_distro_installdeps(undef,$pbos,pb_distro_only_deps_needed($pbos,join(' ',split(/,/,$pkgforpb))));
3522EOF
3523    } else {
3524        # Unknown install type
3525        die("Unknown install type $itype->{$ENV{'PBPROJ'}} for param pbinstalltype");
3526    }
3527    print SCRIPT << 'EOF';
3528pb_system("pb -h",undef,"verbose");
3529pb_system("pbdistrocheck",undef,"verbose");
3530EOF
3531    if ($vtype eq "ve") {
3532            print SCRIPT << 'EOF';
3533# For VE we need to umount some FS at the end
3534
3535pb_system("umount /proc","Unmounting /proc","mayfail");
3536
3537# Create a basic network file if not already there
3538
3539my $nf="/etc/sysconfig/network";
3540if ((! -f $nf) && ($pbos->{'type'} eq "rpm") && ($pbos->{'family'} ne "novell")) {
3541    open(NF,"> $nf") || die "Unable to create $nf";
3542    print NF "NETWORKING=yes\n";
3543    print NF "HOSTNAME=localhost\n";
3544    close(NF);
3545}
3546chmod 0755,$nf;
3547EOF
3548    }
3549
3550    # Adds pb_distro_get_context and all functions needed from ProjectBuilder::Distribution, Conf and Base
3551    foreach my $m ("ProjectBuilder/Base.pm","ProjectBuilder/Distribution.pm","ProjectBuilder/Conf.pm") {
3552        foreach my $d (@INC) {
3553            my $f = "$d/$m";
3554            if (-f "$f") {
3555                open(PBD,"$f") || die "Unable to open $f: $!";
3556                while (<PBD>) {
3557                    next if (/^package/);
3558                    next if (/^use Exporter/);
3559                    next if (/^use ProjectBuilder::/);
3560                    next if (/^our /);
3561                    print SCRIPT $_;
3562                }
3563                close(PBD);
3564                # We just need the first one of each file wrt @INC - hopefully that's the right one.
3565                last;
3566            }
3567        }
3568    }
3569    # Use a fake pb_version_init version here
3570    print SCRIPT << "EOF";
3571sub pb_version_init {
3572
3573return("$projectbuilderver","$projectbuilderrev");
3574}
35751;
3576EOF
3577    close(SCRIPT);
3578    chmod 0755,"$pbscript";
3579
3580    # That build script needs to be run as root and force stop of VM at end
3581    $pbaccount = "root";
3582
3583    # Force shutdown of VM except if it was already launched
3584    my $pbforce = 0;
3585    if ((! $vmexist) && ($vtype eq "vm")) {
3586        $pbforce = 1;
3587    }
3588   
3589    pb_script2v($pbscript,$vtype,$pbforce,$v);
3590    $pm->finish if (defined $pbparallel);
3591}
3592$pm->wait_all_children if (defined $pbparallel);
3593die "Aborting, one or more of the children failed." if ((not $all_ok) && ($Global::pb_stop_on_error));
3594return;
3595}
3596
3597# Function to create a snapshot named 'pb' for VMs and a compressed tar for VEs
3598sub pb_snap2v {
3599
3600my $vtype = shift;
3601
3602my ($vm,$all) = pb_get2v($vtype);
3603
3604# Script generated
3605my $pbscript = "$ENV{'PBDESTDIR'}/snapv.$$";
3606
3607my ($pbac) = pb_conf_get($vtype."login");
3608
3609foreach my $v (@$vm) {
3610    if ($vtype eq "ve") {
3611        # Get distro context
3612        my $pbos = pb_distro_get_context($v);
3613        my ($vepath) = pb_conf_get("vepath");
3614
3615        # Test if an existing snapshot exists and remove it if there is a VE
3616        if ((-f "$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz") &&
3617            (! -d "$vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}")) {
3618                pb_system("sudo rm -f $vepath->{$ENV{'PBPROJ'}}/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz","Removing previous snapshot $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz");
3619        }
3620    }
3621
3622    # Prepare the script to be executed on the VM/VE
3623    open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
3624    print SCRIPT << 'EOF';
3625    #!/bin/bash
3626    sleep 2
3627EOF
3628    close(SCRIPT);
3629    chmod 0755,"$pbscript";
3630
3631    # Force shutdown of VM/VE
3632    # Force snapshot of VM/VE
3633    pb_script2v($pbscript,$vtype,1,$v,1);
3634}
3635return;
3636}
3637
3638# Function to update VMs/VEs/RMs with the latest distribution content
3639sub pb_update2v {
3640
3641my $vtype = shift;
3642
3643my ($vm,$all) = pb_get2v($vtype);
3644
3645# Script generated
3646my $pbscript = "$ENV{'PBDESTDIR'}/updatev.$$";
3647
3648my ($pbac) = pb_conf_get($vtype."login");
3649
3650foreach my $v (@$vm) {
3651    # Get distro context
3652    my $pbos = pb_distro_get_context($v);
3653
3654    # Prepare the script to be executed on the VM/VE/RM
3655    # in $ENV{'PBDESTDIR'}/updatev
3656    open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript";
3657   
3658    print SCRIPT << 'EOF';
3659    #!/bin/bash
3660    sleep 2
3661EOF
3662    # VE needs a good /proc
3663    if ($vtype eq "ve") {
3664        print SCRIPT "sudo /bin/mount -t proc /proc /proc\n";
3665    }
3666    print SCRIPT "$pbos->{'update'}\n";
3667    if ($vtype eq "ve") {
3668        print SCRIPT "sudo /bin/umount /proc\n";
3669    }
3670    close(SCRIPT);
3671    chmod 0755,"$pbscript";
3672
3673    # Force shutdown of VM except
3674    pb_script2v($pbscript,$vtype,1,$v);
3675}
3676return;
3677}
3678
3679sub pb_announce {
3680
3681    my $antype = shift;
3682
3683    # Get all required parameters
3684    my ($pbpackager,$pbrepo) = pb_conf_get("pbpackager","pbrepo");
3685    my ($pkgv, $pkgt, $testver) = pb_conf_get_if("pkgver","pkgtag","testver");
3686    if (((not defined $testver) || (not defined $testver->{$ENV{'PBPROJ'}}) || ($testver->{$ENV{'PBPROJ'}} !~ /true/i)) && ($antype eq "Clean")) {
3687        # We just clean for test versions
3688        pb_log(0,"Unable to clean SSH repository for non testver version\n");
3689        return;
3690    }
3691    my $pkg = pb_cms_get_pkg($defpkgdir,$extpkgdir);
3692    my @pkgs = @$pkg;
3693    my %pkgs;
3694    my $first = 0;
3695
3696    # Get all distros concerned
3697    my $pbos = pb_distro_get_context();
3698    my $distrolist = pb_get_distros($pbos,undef);
3699    my %dl;
3700    my %theorlist;
3701    my %archlist;
3702    foreach my $d (split(/,/,$distrolist)) {
3703        my ($d1,$d2,$d3) = split(/-/,$d);
3704        $dl{$d1}++;
3705    }
3706
3707    # Command to find packages on repo
3708    my $findstr = "find ".join(" ",keys %dl)." ";
3709    my $srcstr = "";
3710    # Generated announce files
3711    my @files;
3712
3713    foreach my $pbpkg (@pkgs) {
3714        if ($first != 0) {
3715            $findstr .= "-o ";
3716        }
3717        $first++;
3718        if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) {
3719            $pbver = $pkgv->{$pbpkg};
3720        } else {
3721            $pbver = $ENV{'PBPROJVER'};
3722        }
3723        if ((defined $pkgt) && (defined $pkgt->{$pbpkg})) {
3724            $pbtag = $pkgt->{$pbpkg};
3725        } else {
3726            $pbtag = $ENV{'PBPROJTAG'};
3727        }
3728
3729        # TODO: use virtual/real names here now
3730        my $pbrealpkg = $pbpkg;
3731        my $pbrealpkgrpm = pb_cms_get_real_pkg($pbpkg,"rpm");
3732        my $pbrealpkgdeb = pb_cms_get_real_pkg($pbpkg,"deb");
3733        if ($antype eq "Clean") {
3734            # We only clean test versions anyway
3735            $pbtag = "0";
3736            my $nver = $pbver;
3737            my $ntag = "[2-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]";
3738            $pbver .= $ntag;
3739            $findstr .= "-name \'$pbrealpkgrpm-$pbver-$pbtag\.*.rpm\' -o -name \'$pbrealpkgrpm-debug-$pbver-$pbtag\.*.rpm\' -o -name \'$pbrealpkgdeb"."_$pbver-$pbtag"."_*\.deb\' -o -name \'$pbrealpkgdeb"."_$pbver-$pbtag.dsc\' -o -name \'$pbrealpkgdeb"."_$pbver-$pbtag.tar.gz\' -o -name \'$pbrealpkg-$nver"."_p$ntag\.ebuild\' -o -name \'$pbrealpkg-$pbver-$pbtag*\.pkg\.gz\' -o -name \'$pbrealpkg-$pbver-$pbtag*\.sd\' ";
3740            $srcstr .= "src/$pbrealpkg-$pbver.tar.gz src/$pbrealpkg-$pbver.pbconf.tar.gz ";
3741        } else {
3742            # "Announce" and "Check"
3743            my @date=pb_get_date();
3744            # the matching is only done on packages made the same day for test version. Hopefully this is enough
3745            my $nver;
3746            if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
3747                $pbtag = "0";
3748                my $ntag .= strftime("%Y%m%d*", @date);
3749                $nver = $pbver."_p$ntag";
3750                $pbver .= $ntag;
3751            } else { 
3752                $nver = $pbver."-r$pbtag";
3753            }
3754            $findstr .= "-name \'$pbrealpkgrpm-$pbver-$pbtag\.*.rpm\' -o -name \'$pbrealpkgdeb"."_$pbver-$pbtag"."_*\.deb\' -o -name \'$pbrealpkg-$nver\.ebuild\' -o -name \'$pbrealpkg-$pbver\.pkg\.gz\' -o -name \'$pbrealpkg-$pbver\.sd\' ";
3755        }
3756
3757        if ($antype eq "Announce") {
3758            my $chglog;
3759
3760            pb_cms_init($pbinit);
3761            # Get project info on log file and generate tmp files used later on
3762            $chglog = "$ENV{'PBROOTDIR'}/$pbpkg/pbcl";
3763            $chglog = "$ENV{'PBROOTDIR'}/pbcl" if (! -f $chglog);
3764            $chglog = undef if (! -f $chglog);
3765
3766            open(OUT,"> $ENV{'PBTMP'}/$pbpkg.ann") || die "Unable to create $ENV{'PBTMP'}/$pbpkg.ann: $!";
3767            my $pb;
3768            $pb->{'realpkg'} = $pbrealpkg;
3769            $pb->{'ver'} = $pbver;
3770            $pb->{'tag'} = $pbtag;
3771            $pb->{'date'} = $pbdate;
3772            $pb->{'extdir'} = pb_get_extdir();
3773            $pb->{'chglog'} = $chglog;
3774            $pb->{'packager'} = $pbpackager;
3775            $pb->{'proj'} = $ENV{'PBPROJ'};
3776            $pb->{'repo'} = $pbrepo;
3777            $pb->{'pbos'}->{'type'} = "announce";
3778            $pb->{'pbos'}->{'suffix'} = "none";
3779            pb_changelog($pb,\*OUT,"yes");
3780            close(OUT);
3781            push(@files,"$ENV{'PBTMP'}/$pbpkg.ann");
3782        } elsif ($antype eq "Check") {
3783            # For the check we also build the theoritical complete list we should get
3784            foreach my $d (split(/,/,$distrolist)) {
3785                $pbos = pb_distro_get_context($d);
3786                if ($pbos->{'type'} eq "rpm") {
3787                    $theorlist{"$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/$pbrealpkgrpm-$pbver-$pbtag$pbos->{'suffix'}"} = 0;
3788                } elsif ($pbos->{'type'} eq "deb") {
3789                    $theorlist{"$pbos->{'name'}/$pbos->{'version'}/$pbrealpkgdeb"."_$pbver-$pbtag"} = 0;
3790                    # TODO are we always using the last arch ?
3791                    $archlist{"$pbos->{'name'}/$pbos->{'version'}/$pbrealpkgdeb"."_$pbver-$pbtag"} = "$pbos->{'arch'}";
3792                } elsif ($pbos->{'type'} eq "ebuild") {
3793                    my $prefix = "-r";
3794                    $prefix = "_p" if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i));
3795                    $theorlist{"$pbos->{'name'}/$pbos->{'version'}/$pbrealpkg-$pbver$prefix$pbtag.ebuild"} = 0;
3796                    $archlist{"$pbos->{'name'}/$pbos->{'version'}/$pbrealpkg-$pbver$prefix$pbtag.ebuild"} = "$pbos->{'arch'}";
3797                } elsif ($pbos->{'type'} eq "pkg") {
3798                    $theorlist{"$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/$pbrealpkg-$pbver-$pbtag.pkg.gz"} = 0;
3799                } else {
3800                    pb_log(1,"No theoritical list possible for type $pbos->{'type'}\n");
3801                }
3802            }
3803        }
3804        pb_log(2,"theorlist : ".Dumper(%theorlist)."\n");
3805    }
3806    if ($antype eq "Announce") {
3807        $findstr .= " | grep -Ev \'src.rpm\'";
3808    } elsif ($antype eq "Clean") {
3809        $findstr .= " | xargs rm -f -v $srcstr ";
3810    }
3811
3812    # Prepare the command to run and execute it
3813    open(PBS,"> $ENV{'PBTMP'}/pbscript") || die "Unable to create $ENV{'PBTMP'}/pbscript";
3814    print PBS "#!/bin/bash\n";
3815    print PBS "set -x\n" if ($pbdebug gt 1);
3816    print PBS "$findstr | sort 2> /dev/null\n";
3817    close(PBS);
3818    chmod 0755,"$ENV{'PBTMP'}/pbscript";
3819    pb_send2target("Announce");
3820
3821    my $sl = "Project $ENV{'PBPROJ'} version $ENV{'PBPROJVER'} is now available";
3822    if ($antype eq "Announce") {
3823        # Get subject line
3824        pb_log(0,"Please enter the title of your announce\n");
3825        pb_log(0,"(By default: $sl)\n");
3826        my $sl2 = <STDIN>;
3827        $sl = $sl2 if ($sl2 !~ /^$/);
3828
3829        # Prepare a template of announce
3830        open(ANN,"> $ENV{'PBTMP'}/announce.html") || die "Unable to create $ENV{'PBTMP'}/announce.html: $!";
3831        print ANN << "EOF";
3832$sl</p>
3833
3834<p>The project team is happy to announce the availability of a newest version of $ENV{'PBPROJ'} $ENV{'PBPROJVER'}. Enjoy it as usual!</p>
3835<p>
3836Now available at <a href="$pbrepo->{$ENV{'PBPROJ'}}">$pbrepo->{$ENV{'PBPROJ'}}</a>
3837</p>
3838<p>
3839EOF
3840    }
3841
3842    open(LOG,"$ENV{'PBTMP'}/system.$$.log") || die "Unable to read $ENV{'PBTMP'}/system.$$.log: $!";
3843    if ($antype eq "Announce") {
3844        my $col = 2;
3845        my $i = 1;
3846        print ANN << 'EOF';
3847<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0">
3848<TR>
3849EOF
3850        while (<LOG>) {
3851            print ANN "<TD><A HREF=\"$pbrepo->{$ENV{'PBPROJ'}}/$_\">$_</A></TD>";
3852            $i++;
3853            if ($i > $col) {
3854                print ANN "</TR>\n<TR>";
3855                $i = 1;
3856            }
3857        }
3858    } elsif ($antype eq "Clean") {
3859        while (<LOG>) {
3860            # skip errors
3861            next if ($_ !~ /^removed /);
3862            pb_log(0,"$_");
3863        }
3864    } else {
3865        # In "Check" mode we need to compare the 2 lists (real and theoritical)
3866        while (<LOG>) {
3867            # Get package name and remove what is in extra for the theoritical list (arch at the end)
3868            chomp();
3869            # skip find errors
3870            next if (/^find:/);
3871            my $p = $_;
3872            $p =~ s/\.(i[3456]86|x86_64|noarch|src)\.rpm$//;
3873            $p =~ s/_(i[3456]86|amd64|all)\.deb$//;
3874            $p =~ s/(-0\.[0-9]{8})[0-9]{6}/$1*/ if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i));
3875            $p =~ s/(-r|_p[0-9]+)\.ebuild/$1*/ if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i));
3876            $theorlist{$p} = -2 if (not defined $theorlist{$p});
3877            $theorlist{$p} = $theorlist{$p} + 1;
3878        }
3879        pb_log(2,"theorlist : ".Dumper(%theorlist)."\n");
3880    }
3881    close(LOG);
3882
3883    # Nothing more for the cleanssh case
3884    return if ($antype eq "Clean");
3885
3886    if ($antype eq "Check") {
3887        my ($chkex) = pb_conf_get_if("checkexclude");
3888        my $vmbuildlist = "";
3889        my $vebuildlist = "";
3890        my $rmbuildlist = "";
3891        my @pt = pb_conf_get_if("vmlist","velist","rmlist");
3892        foreach my $t (sort keys %theorlist) {
3893            if (defined $theorlist{$t} and $theorlist{$t} >= 1) {
3894                pb_log(1,"Packages found for $t\n");
3895            } elsif (defined $theorlist{$t} and $theorlist{$t} < 0) {
3896                pb_log(0,"Extra Package found for $t\n");
3897            } else {
3898                pb_log(2,"Analyzing $t\n");
3899                my ($os,$ver,$arch,$package) = split(/\//,$t);
3900                # Some distro have no arch subdir
3901                if (not defined $package) {
3902                    $package = $arch;
3903                    # TODO: If both arch have failed, we just make the last one
3904                    $arch = $archlist{$t};
3905                }
3906                my $pbos = pb_distro_get_context("$os-$ver-$arch");
3907                my $pkgn = $package;
3908                if ($pbos->{'type'} ne "deb") {
3909                    # package name is more easily found from the end for non deb
3910                    # as '-' is the separator, but it can also be used in names
3911                    $pkgn = reverse($package);
3912                    # search the second '-' and isolate the now last part which is the full name
3913                    $pkgn =~ s/([^-]+)-([^-]+)-([\S])+$/$3/;
3914                } else {
3915                    $pkgn =~ s/([^_]+)_([\S])+$/$2/;
3916                }
3917                my $found = 0;
3918                # Handle the exclusion of OSes
3919                my $excl = "";
3920                $excl .= $chkex->{$pkgn} if (defined $chkex->{$pkgn});
3921                $excl .= $chkex->{"all"} if (defined $chkex->{"all"});
3922
3923                pb_log(2,"Searching in excl $excl\n");
3924                foreach my $ex (split(/,/,$excl)) {
3925                    $found = 1 if ("$os-$ver-$arch" =~ /^$ex/);
3926                }
3927                # Skip as excluded
3928                next if ($found == 1);
3929                pb_log(0,"Package NOT found for $t\n");
3930                # Avoid duplicates in list
3931                next if ($vmbuildlist =~ /$os-$ver-$arch/);
3932                next if ($vebuildlist =~ /$os-$ver-$arch/);
3933                next if ($rmbuildlist =~ /$os-$ver-$arch/);
3934                # check with which method we need to build
3935                if ((defined $pt[0]->{$ENV{'PBPROJ'}}) and ($pt[0]->{$ENV{'PBPROJ'}} =~ /$os-$ver-$arch/)) {
3936                    $vmbuildlist = "$os-$ver-$arch" if ($vmbuildlist eq "");
3937                    $vmbuildlist .= ",$os-$ver-$arch" if ($vmbuildlist !~ /$os-$ver-$arch/);
3938                    next;
3939                }
3940                if ((defined $pt[1]->{$ENV{'PBPROJ'}}) and ($pt[1]->{$ENV{'PBPROJ'}} =~ /$os-$ver-$arch/)) {
3941                    $vebuildlist = "$os-$ver-$arch" if ($vebuildlist eq "");
3942                    $vebuildlist .= ",$os-$ver-$arch" if ($vebuildlist !~ /$os-$ver-$arch/);
3943                    next;
3944                }
3945                if ((defined $pt[2]->{$ENV{'PBPROJ'}}) and ($pt[2]->{$ENV{'PBPROJ'}} =~ /$os-$ver-$arch/)) {
3946                    $rmbuildlist = "$os-$ver-$arch" if ($rmbuildlist eq "");
3947                    $rmbuildlist .= ",$os-$ver-$arch" if ($rmbuildlist !~ /$os-$ver-$arch/);
3948                }
3949            }
3950        }
3951        # If we want to rebuild automatically, let's do it
3952        if (defined $opts{'rebuild'}) {
3953            # SandBox or CMS
3954            pb_log(0,"Rebuilding from SandBox\n");
3955            pb_log(0,"for VMs: $vmbuildlist\n") if ($vmbuildlist ne "");
3956            pb_log(0,"for VEs: $vebuildlist\n") if ($vebuildlist ne "");
3957            pb_log(0,"for RMs: $rmbuildlist\n") if ($rmbuildlist ne "");
3958            pb_cms2build("SandBox");
3959            # Which mode
3960            $ENV{'PBV'} = $vmbuildlist;
3961            pb_build2v("vm","build") if ($vmbuildlist ne "");
3962            $ENV{'PBV'} = $vebuildlist;
3963            pb_build2v("ve","build") if ($vebuildlist ne "");
3964            $ENV{'PBV'} = $rmbuildlist;
3965            pb_build2v("rm","build") if ($rmbuildlist ne "");
3966        }
3967        # For the check part this is now finished
3968        return;
3969    }
3970
3971    print ANN << "EOF";
3972</TR>
3973</TABLE>
3974</p>
3975
3976<p>As usual source packages are also available in the same directory.</p>
3977
3978<p>
3979Changes are :
3980</p>
3981<p>
3982EOF
3983    # Get each package changelog content
3984    foreach my $f (sort(@files)) {
3985        open(IN,"$f") || die "Unable to read $f:$!";
3986        while (<IN>) {
3987            print ANN $_;
3988        }
3989        close(IN);
3990        print ANN "</p><p>\n";
3991    }
3992    print ANN "</p>\n";
3993    close(ANN);
3994
3995    # Allow for modification
3996    my $editor = "vi";
3997    $editor = $ENV{'EDITOR'} if (defined $ENV{'EDITOR'});
3998    pb_system("$editor $ENV{'PBTMP'}/announce.html","Allowing modification of the announce","noredir");
3999
4000    # Store it in DB for external usage (Web pages generation)
4001    my $db = "$ENV{'PBCONFDIR'}/announces3.sql";
4002
4003    my $precmd = "";
4004    if (! -f $db) {
4005        $precmd = "CREATE TABLE announces (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATE, announce VARCHAR[65535])";
4006    }
4007
4008    my $dbh = DBI->connect("dbi:SQLite:dbname=$db","","",
4009                        { RaiseError => 1, AutoCommit => 1 })
4010                        || die "Unable to connect to $db";
4011
4012    if ($precmd ne "") {
4013        my $sth = $dbh->prepare(qq{$precmd})
4014                    || die "Unable to create table into $db";
4015        $sth->execute();
4016    }
4017
4018    # To read whole file
4019    local $/;
4020    open(ANN,"$ENV{'PBTMP'}/announce.html") || die "Unable to read $ENV{'PBTMP'}/announce.html: $!";
4021    my $announce = <ANN>;
4022    close(ANN);
4023   
4024    pb_log(2,"INSERT INTO announces VALUES (NULL, $pbdate, $announce)");
4025    my $sth = $dbh->prepare(qq{INSERT INTO announces VALUES (NULL,?,?)})
4026                    || die "Unable to insert into $db";
4027    $sth->execute($pbdate, $announce);
4028    $sth->finish();
4029    $dbh->disconnect;
4030
4031    # Then deliver it on the Web
4032    # $TOOLHOME/livwww www
4033
4034    # Mail it to project's ML
4035    open(ML,"| w3m -dump -T text/html > $ENV{'PBTMP'}/announce.txt") || die "Unable to create $ENV{'PBTMP'}/announce.txt: $!";
4036    print ML << 'EOF';
4037<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/x html1/DTD/xhtml1-strict.dtd">
4038
4039<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="en" lang="en">
4040  <head>
4041  </head>
4042  <body>
4043  <p>
4044EOF
4045    open(ANN,"$ENV{'PBTMP'}/announce.html") || die "Unable to read $ENV{'PBTMP'}/announce.html: $!";
4046    while(<ANN>) {
4047        print ML $_;
4048    }
4049    print ML << 'EOF';
4050</body>
4051</html>
4052EOF
4053    close(ML);
4054
4055    # To read whole file
4056    local $/;
4057    open(ANN,"$ENV{'PBTMP'}/announce.txt") || die "Unable to read $ENV{'PBTMP'}/announce.txt: $!";
4058    my $msg = <ANN>;
4059    close(ANN);
4060   
4061    # Preparation of headers
4062    eval
4063    {
4064        require Mail::Sendmail;
4065        Mail::Sendmail->import();
4066    };
4067    if ($@) {
4068        # Mail::Sendmail not found not sending mail !
4069        pb_log(0,"No Mail::Sendmail module found so not sending any mail !\n");
4070    } else {
4071        my ($pbml,$pbsmtp) = pb_conf_get("pbml","pbsmtp");
4072        my %mail = (   
4073            To          =>  $pbml->{$ENV{'PBPROJ'}},
4074            From        =>  $pbpackager->{$ENV{'PBPROJ'}},
4075            Smtp        =>  $pbsmtp->{$ENV{'PBPROJ'}},
4076            Body        =>  $msg,
4077            Subject     =>  "[ANNOUNCE] $sl",
4078        );
4079           
4080        # Send mail
4081        if (! sendmail(%mail)) {
4082            if ((defined $Mail::Sendmail::error) and (defined $Mail::Sendmail::log)) {
4083                die "Unable to send mail ($Mail::Sendmail::error): $Mail::Sendmail::log";
4084            }
4085        }
4086    }
4087}
4088
4089#
4090# Creates a set of HTML file containing the news for the project
4091# based on what has been generated by the pb_announce function
4092#
4093sub pb_web_news2html {
4094
4095    my $dest = shift || $ENV{'PBTMP'};
4096
4097    # Get all required parameters
4098    my ($pkgv, $pkgt) = pb_conf_get_if("pkgver","pkgtag");
4099
4100    # DB of announces for external usage (Web pages generation)
4101    my $db = "$ENV{'PBCONFDIR'}/announces3.sql";
4102
4103    my $dbh = DBI->connect("dbi:SQLite:dbname=$db","","",
4104                        { RaiseError => 1, AutoCommit => 1 })
4105                        || die "Unable to connect to $db";
4106    # For date handling
4107    $ENV{LANGUAGE}="C";
4108    my $firstjan = strftime("%Y-%m-%d", 0, 0, 0, 1, 0, localtime->year(), 0, 0, -1);
4109    my $oldfirst = strftime("%Y-%m-%d", 0, 0, 0, 1, 0, localtime->year()-1, 0, 0, -1);
4110    pb_log(2,"firstjan: $firstjan, oldfirst: $oldfirst, pbdate:$pbdate\n");
4111    my $all = $dbh->selectall_arrayref("SELECT id,date,announce FROM announces ORDER BY date DESC");
4112    my %news;
4113    $news{"cy"} = "";   # current year's news
4114    $news{"ly"} = "";   # last year news
4115    $news{"py"} = "";   # previous years news
4116    $news{"fp"} = "";   # first page news
4117    my $cpt = 4;        # how many news for first page
4118    # Extract info from DB
4119    foreach my $row (@$all) {
4120        my ($id, $date, $announce) = @$row;
4121        $news{"cy"} = $news{"cy"}."<p><B>$date</B> $announce\n" if ((($date cmp $pbdate) le 0) && (($firstjan cmp $date) le 0));
4122        $news{"ly"} = $news{"ly"}."<p><B>$date</B> $announce\n" if ((($date cmp $firstjan) le 0) && (($oldfirst cmp $date) le 0));
4123        $news{"py"} = $news{"py"}."<p><B>$date</B> $announce\n" if (($date cmp $oldfirst) le 0);
4124        $news{"fp"} = $news{"fp"}."<p><B>$date</B> $announce\n" if ($cpt > 0);
4125        $cpt--;
4126    }
4127    pb_log(1,"news{fp}: ".$news{"fp"}."\n");
4128    $dbh->disconnect;
4129
4130    # Generate the HTML content
4131    foreach my $pref (keys %news) {
4132        open(NEWS,"> $dest/pb_web_$pref"."news.html") || die "Unable to create $dest/pb_web_$pref"."news.html: $!";
4133        print NEWS "$news{$pref}";
4134        close(NEWS);
4135    }
4136}
4137
4138
4139# Return the SSH key file to use
4140# Potentially create it if needed
4141
4142sub pb_ssh_get {
4143
4144my $create = shift || 0;    # Do not create keys by default
4145
4146my ($pbagent) = pb_conf_get_if("pbusesshagent");
4147# use ssh-agent if asked so.
4148return(undef) if (($create == 0) && (defined $pbagent->{$ENV{'PBPROJ'}}) && ($pbagent->{$ENV{'PBPROJ'}} =~ /true/io));
4149
4150# Check the SSH environment
4151my $keyfile = undef;
4152
4153# We have specific keys by default
4154$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa";
4155if (!(-e $keyfile) && ($create eq 1)) {
4156    pb_system("ssh-keygen -q -b 1024 -N '' -f $keyfile -t dsa","Generating SSH keys for pb");
4157}
4158
4159$keyfile = "$ENV{'HOME'}/.ssh/id_rsa" if (-s "$ENV{'HOME'}/.ssh/id_rsa");
4160$keyfile = "$ENV{'HOME'}/.ssh/id_dsa" if (-s "$ENV{'HOME'}/.ssh/id_dsa");
4161$keyfile = "$ENV{'HOME'}/.ssh/pb_dsa" if (-s "$ENV{'HOME'}/.ssh/pb_dsa");
4162die "Unable to find your public ssh key under $ENV{'HOME'}/.ssh" if (not defined $keyfile);
4163return($keyfile);
4164}
4165
4166
4167# Returns the pid of a running VM command using a specific VM file, and the port used if the VM exists
4168sub pb_check_ps {
4169    my $vmcmd = shift;
4170    my $vmm = shift;
4171    my $vmexist = 0;        # FALSE by default
4172    my $vmport = undef;         # NONE by default
4173
4174    open(PS, "ps auxhww|") || die "Unable to call ps";
4175    while (<PS>) {
4176        next if (! /$vmcmd/);
4177        next if (! /$vmm/);
4178        my ($void1, $void2);
4179        ($void1, $vmexist, $vmport) = split(/ +/,$_,3);
4180        pb_log(2,"pb_check_ps $vmport\n");
4181        $vmport =~ s/.*\stcp\:([0-9]+)\:10.0.2.15:22.*/$1/;
4182        chomp($vmport);
4183        pb_log(2,"pb_check_ps found a VM $vmexist using port $vmport\n");
4184        last;
4185    }
4186    # Maintain compatibility by just returning PID if no port
4187    return($vmexist,$vmport) if (defined $vmport);
4188    return($vmexist);
4189}
4190
4191
4192sub pb_extract_build_files {
4193
4194my $src=shift;
4195my $dir=shift;
4196my $ddir=shift;
4197my $mandatory=shift || "spec";
4198my @files;
4199
4200my $flag = "mayfail" if (($mandatory eq "patch") || ($mandatory eq "src"));
4201my $res;
4202
4203if ($src =~ /tar\.gz$/) {
4204    $res = pb_system("tar xfpz $src $dir","Extracting $mandatory files from $src",$flag);
4205} elsif ($src =~ /tar\.bz2$/) {
4206    $res = pb_system("tar xfpj $src $dir","Extracting $mandatory files from $src",$flag);
4207} else {
4208    die "Unknown compression algorithm for $src";
4209}
4210# If not mandatory return now
4211return() if (($res != 0) and (($mandatory eq "patch") || ($mandatory eq "src")));
4212opendir(DIR,"$dir") || die "Unable to open directory $dir: $!";
4213foreach my $f (readdir(DIR)) {
4214    next if ($f =~ /^\./);
4215    # Skip potential patch dir
4216    next if ($f =~ /^pbpatch/);
4217    # Skip potential source dir
4218    next if ($f =~ /^pbsrc/);
4219    # Skip potential backup files
4220    next if ($f =~ /~$/);
4221    move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir";
4222    pb_log(2,"mv $dir/$f $ddir\n");
4223    push @files,"$ddir/$f";
4224}
4225closedir(DIR);
4226# Not enough but still a first cleanup
4227pb_rm_rf("$dir");
4228return(@files);
4229}
4230
4231sub pb_list_bfiles {
4232
4233my $dir = shift;
4234my $pbpkg = shift;
4235my $bfiles = shift;
4236my $pkgfiles = shift;
4237my $supfiles = shift;
4238# subdir to keep if recursive mode, empty by default
4239my $subdir = shift || "";
4240# In a recursive function , we need a local var as DIR handle
4241my $bdir;
4242
4243pb_log(2,"DEBUG: entering pb_list_bfiles in $dir: ".Dumper($bfiles)."\n");
4244opendir($bdir,"$dir") || die "Unable to open dir $dir: $!";
4245foreach my $f (readdir($bdir)) {
4246    pb_log(3,"DEBUG: pb_list_bfiles found $f\n");
4247    next if ($f =~ /^\./);
4248    if (-d "$dir/$f") {
4249        # Recurse for directories (Debian 3.0 format e.g.)
4250        pb_log(2,"DEBUG: pb_list_bfiles recurse in $dir/$f\n");
4251        pb_list_bfiles("$dir/$f",$pbpkg,$bfiles,$pkgfiles,$supfiles,$f);
4252        next;
4253    }
4254
4255    my $key = $f;
4256    # if recursive then store also the subdir
4257    $key = "$subdir/$f" if ($subdir ne "");
4258    $bfiles->{$key} = "$dir/$f";
4259    $bfiles->{$key} =~ s~$ENV{'PBROOTDIR'}~~;
4260    if (defined $supfiles->{$pbpkg}) {
4261        $pkgfiles->{$key} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/);
4262    }
4263}
4264closedir($bdir);
4265pb_log(2,"DEBUG: exiting pb_list_bfiles: ".Dumper($bfiles)."\n");
4266}
4267
4268sub pb_add_comma {
4269
4270my $str = shift;
4271my $addstr = shift;
4272
4273$str .= "," if (defined $str);
4274$str .= $addstr;
4275return($str);
4276}
4277
4278sub pb_list_sfiles {
4279
4280my $sdir = shift;
4281my $ptr = shift;
4282my $pbos = shift;
4283my $extdir = shift;
4284
4285pb_log(2,"DEBUG: entering pb_list_sfiles: ".Dumper($ptr)."\n");
4286my $key = "$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}";
4287
4288# Prepare local sources for this distro - They are always applied first - May be a problem one day
4289# This function works for both patches and additional sources
4290foreach my $p (sort(<$sdir/*>)) {
4291    $ptr->{$key} = pb_add_comma($ptr->{$key},"file://$p") if (($p =~ /\.all$/) || ($p =~ /\.$pbos->{'os'}$/) || ($p =~ /\.$pbos->{'type'}$/) || ($p =~ /\.$pbos->{'family'}$/) || ($p =~ /\.$pbos->{'name'}$/) || ($p =~ /\.$pbos->{'name'}-$pbos->{'version'}$/) ||($p =~ /\.$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}$/));
4292}
4293
4294# Prepare also remote sources to be included - Applied after the local ones
4295foreach my $p ("all","$pbos->{'os'}","$pbos->{'type'}","$pbos->{'family'}","$pbos->{'name'}","$pbos->{'name'}-$pbos->{'version'}","$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}") {
4296    my $f = "$extdir.".".$p";
4297    next if (not -f $f);
4298    if (not open(PATCH,$f)) {
4299        pb_display("Unable to open existing external source file content $f\n");
4300        next;
4301    }
4302    while (<PATCH>) {
4303        chomp();
4304        $ptr->{$key} = pb_add_comma($ptr->{$key},"$_");
4305    }
4306    close(PATCH);
4307}
4308pb_log(2,"DEBUG: exiting pb_list_sfiles: ".Dumper($ptr)."\n");
4309return($ptr);
4310}
4311   
4312#
4313# Return the list of packages we are working on in a non CMS action
4314#
4315sub pb_get_pkg {
4316
4317my @pkgs = ();
4318
4319# In script actions that file may not exist.
4320return(\@pkgs) if ((not defined $ENV{'PBDESTDIR'}) || (not defined $ENV{'PBPROJVER'}) || (not defined $ENV{'PBPROJTAG'}) || (! -f "$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb"));
4321
4322my ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg");
4323@pkgs = keys %$var if (defined $var);
4324
4325pb_log(0,"Packages: ".join(',',@pkgs)."\n") if (@pkgs);
4326return(\@pkgs);
4327}
4328
4329# Manages VM/RM SSH port communication
4330sub pb_get_port {
4331
4332my $port = shift;
4333my $pbos = shift;
4334my $cmt = shift;
4335my $nport;
4336
4337die "No port passed in parameter. Report to dev team\n" if (not defined $port);
4338# key is project on VM, but machine tuple for RM
4339if ($cmt =~ /^RM/i) {
4340    $nport = $port->{"$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}"};
4341} else {
4342    $nport = $port->{$ENV{'PBPROJ'}};
4343}
4344pb_log(2,"pb_get_port with $nport\n");
4345if ($cmt =~ /^VM/i) {
4346    # Maybe a port was given as parameter so overwrite
4347    $nport = "$pbport" if (defined $pbport);
4348    # Maybe in // mode so use the env var set up as an offset to the base port
4349    $nport += $ENV{'PBVMPORT'} if ((defined $pbparallel) && (defined $ENV{'PBVMPORT'}));
4350}
4351pb_log(2,"pb_get_port returns $nport\n");
4352return($nport);
4353}
4354
4355sub pb_set_port { 
4356       
4357my ($pid,$ident) = @_;
4358pb_log(2,"pb_set_port for VM ($pid), id $ident\n");
4359$ENV{'PBVMPORT'} = $ident;
4360pb_log(2,"pb_set_port sets PBVMPORT in env to $ENV{'PBVMPORT'}\n");
4361}
4362
4363sub pb_set_parallel {
4364
4365my $vtype = shift;
4366
4367pb_log(2,"pb_set_parallel vtype: $vtype\n");
4368# Take care of memory size if VM, parallel mode and more than 1 action
4369if ((defined $pbparallel) && ($pbparallel ne 1) && ($vtype eq "vm")) {
4370    eval
4371    {
4372        require Linux::SysInfo;
4373        Linux::SysInfo->import();
4374    };
4375    if ($@) {
4376        # Linux::SysInfo not found
4377        pb_log(1,"ADVISE: Install Linux::SysInfo to benefit from automatic parallelism optimization.\nOr optimize manually pbparallel in your pb.conf file\nUsing $pbparallel processes max at a time for the moment\nWARNING: This may consume too much memory for your system\n");
4378    } else {
4379        # Using the memory size
4380        my $si = Linux::SysInfo::sysinfo();
4381        if (not defined $si) {
4382            pb_log(1,"ADVISE: Install Linux::SysInfo to benefit from automatic parallelism optimization.\nOr optimize manually pbparallel in your pb.conf file\nUsing $pbparallel processes max at a time for the moment\nWARNING: This may consume too much memory for your system\n");
4383        } else {
4384            # Keep the number of VM whose memory can be allocated
4385            my $ram = $si->{"totalram"}-$si->{"sharedram"}-$si->{"bufferram"};
4386            my $ram2;
4387            my ($vmmem) = pb_conf_get_if("vmmem");
4388
4389            my $v = "default";
4390            if ((defined $vmmem) and (defined $vmmem->{$v})) {
4391                $ram2 = $vmmem->{$v};
4392            } else {
4393                # Default for KVM/QEMU
4394                $ram2 = 128;
4395            }
4396            $pbparallel = sprintf("%d",$ram/$ram2);
4397        }
4398        pb_log(1,"Using $pbparallel processes at a time\n");
4399    }
4400}
4401pb_log(2,"pb_set_parallel returns: $pbparallel\n") if (defined $pbparallel);
4402return($pbparallel);
4403}
4404
4405sub pb_get_sudocmds { 
4406       
4407my $pbos = shift;
4408my @cmds = @_;
4409my %sudocmds;
4410
4411pb_log(2,"pb_get_sudocmds entering with lines:".Dumper(@cmds)."\n");
4412foreach my $c (split(/;/,$pbos->{'update'}),split(/;/,$pbos->{'install'}),@cmds) {
4413    pb_log(2,"pb_get_sudocmds analyses $c\n");
4414    next if ($c !~ /^\s*sudo/);
4415    # remove sudo and leading spaces
4416    $c =~ s/^\s*sudo\s+//;
4417    # keep only the command, not the params
4418    $c =~ s/([^\s]+)\s.*$/$1/;
4419    $sudocmds{$c} = "";
4420}
4421pb_log(2,"pb_get_sudocmds returns ".Dumper(keys %sudocmds)."\n");
4422return(keys %sudocmds);
4423}
4424
4425sub pb_sign_pkgs {
4426
4427my $pbos = shift;
4428my $made = shift;
4429
4430pb_log(2,"entering pb_sign_pkg: $made ".Dumper($pbos)."\n");
4431my ($passfile, $passphrase, $passpath) = pb_conf_get_if("pbpassfile","pbpassphrase","pbpasspath");
4432$ENV{'PBPASSPHRASE'} = $passphrase->{$ENV{'PBPROJ'}} if ((not defined $ENV{'PBPASSPHRASE'}) && (defined $passphrase->{$ENV{'PBPROJ'}}));
4433$ENV{'PBPASSFILE'} = $passfile->{$ENV{'PBPROJ'}} if ((not defined $ENV{'PBPASSFILE'})&& (defined $passfile->{$ENV{'PBPROJ'}})) ;
4434$ENV{'PBPASSPATH'} = $passpath->{$ENV{'PBPROJ'}} if ((not defined $ENV{'PBPASSPATH'})&& (defined $passpath->{$ENV{'PBPROJ'}})) ;
4435
4436# Remove extra spaces
4437$made =~ s/\s+/ /g;
4438$made =~ s/^\s//g;
4439$made =~ s/\s$//g;
4440
4441if ($pbos->{'type'} eq "rpm") {
4442    eval
4443    {
4444        require RPM4::Sign;
4445        RPM4::Sign->import();
4446    };
4447    if ($@) {
4448        # RPM4::Sign not found
4449        pb_log(1,"WARNING: Install RPM4::Sign to benefit from automatic package signing.\n");
4450    } else {
4451        return if ((not defined $ENV{'PBPASSPHRASE'}) and (not defined $ENV{'PBPASSFILE'}));
4452        my $sign = RPM4::Sign->new(
4453            passphrase => $ENV{'PBPASSPHRASE'},
4454            name => $ENV{'PBPACKAGER'},
4455            path => $ENV{'PBPASSPATH'},
4456            password_file => $ENV{'PBPASSFILE'}, 
4457        );
4458
4459        pb_log(0,"Signing RPM packages...\n");
4460        pb_log(2,"pb_sign_pkg: pkgs:".Dumper(split(/ /,$made))."\n");
4461        $sign->rpmssign(split(/ /,$made));
4462    }
4463} elsif ($pbos->{'type'} eq "deb") {
4464    my $changes = "";
4465    foreach my $c (split(/ /,$made)) {
4466        $changes .= " $ENV{'PBBUILDDIR'}/$c" if (($c =~ /\.changes$/) && (-f "$ENV{PBBUILDDIR}/$c"));
4467    }
4468    my $debsigncmd = pb_check_req("debsign",1);
4469    pb_system("$debsigncmd -m\'$ENV{'PBPACKAGER'}\' $changes","Signing DEB packages","mayfail") if (($changes ne "") && (defined $debsigncmd));
4470} else {
4471    pb_log(0,"I don't know yet how to sign packages for type $pbos->{'type'}.\nPlease give feedback to dev team\n");
4472}
4473pb_log(2,"exiting pb_sign_pkg\n");
4474}
4475
4476# return list of all distributins supported, comma separated
4477sub pb_get_distros {
4478
4479my $pbos = shift;
4480my $pbtarget = shift;
4481
4482my @dists = ("$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}");
4483
4484# Get list of distributions for which we need to generate build files if no target
4485if (not defined $pbtarget) {
4486    my @pt = pb_conf_get_if("vmlist","velist","rmlist");
4487    foreach my $pt (@pt) {
4488        push(@dists, split(/,/, $pt->{$ENV{PBPROJ}})) if defined $pt->{$ENV{PBPROJ}};
4489    }
4490    # remove any whitespace
4491    grep(s/\s+//go, @dists); 
4492}
4493return(join(",",@dists));
4494}   
4495
4496sub pb_get_extdir () {
4497
4498    # the pbrc file should contain it and whatever the key, we take it
4499    my ($ed) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","pbextdir");
4500    pb_log(2,"ed: ".Dumper($ed)."\n");
4501    my $pbextdir = "";
4502    foreach my $k (keys %$ed) {
4503        $pbextdir = $ed->{$k};
4504        # In case we have an empty field, empty it completely
4505        pb_log(2,"pbextdir: ***$pbextdir***\n");
4506        $pbextdir =~ s/^\s*$//;
4507    }
4508    pb_log(2,"pbextdir: ***$pbextdir***\n");
4509    return($pbextdir);
4510}
4511
45121;
Note: See TracBrowser for help on using the repository browser.