source: devel/pb/bin/pb @ 1367

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