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

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