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

Last change on this file since 1630 was 1630, checked in by Bruno Cornec, 12 years ago

r4913@localhost: bruno | 2012-06-05 03:13:30 +0200

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