source: ProjectBuilder/devel/pb/lib/ProjectBuilder/CMS.pm@ 1801

Last change on this file since 1801 was 1801, checked in by Bruno Cornec, 10 years ago
  • Fix PBREVISION computation for git-svn
  • Export correctly in case of git-svn as well
File size: 14.9 KB
Line 
1#!/usr/bin/perl -w
2#
3# Project Builder CMS module
4# CMS subroutines brought by the the Project-Builder project
5# which can be easily used by pbinit scripts
6#
7# $Id$
8#
9# Copyright B. Cornec 2007-2012
10# Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard
11# Provided under the GPL v2
12
13package ProjectBuilder::CMS;
14
15use strict 'vars';
16use Carp 'confess';
17use Data::Dumper;
18use English;
19use File::Basename;
20use File::Copy;
21use POSIX qw(strftime);
22use lib qw (lib);
23use ProjectBuilder::Version;
24use ProjectBuilder::Base;
25use ProjectBuilder::Conf;
26use ProjectBuilder::VCS;
27
28# Inherit from the "Exporter" module which handles exporting functions.
29
30use vars qw($VERSION $REVISION @ISA @EXPORT);
31use Exporter;
32
33# Export, by default, all the functions into the namespace of
34# any code which uses this module.
35
36our @ISA = qw(Exporter);
37our @EXPORT = qw(pb_cms_init pb_cms_checkin pb_cms_get_pkg pb_cms_get_real_pkg pb_cms_compliant pb_cms_log);
38($VERSION,$REVISION) = pb_version_init();
39
40=pod
41
42=head1 NAME
43
44ProjectBuilder::CMS, part of the project-builder.org
45
46=head1 DESCRIPTION
47
48This modules provides configuration management system functions suitable for pbinit calls.
49
50=head1 USAGE
51
52=over 4
53
54=item B<pb_cms_init>
55
56This function setup the environment for the CMS system related to the URL given by the pburl configuration parameter.
57The potential parameter indicates whether we should inititate the context or not.
58It sets up environement variables (PBPROJDIR, PBDIR, PBREVISION, PBCMSLOGFILE)
59
60=cut
61
62sub pb_cms_init {
63
64my $pbinit = shift || undef;
65my $param = shift || undef;
66
67my ($pburl) = pb_conf_get("pburl");
68pb_log(2,"DEBUG: Project URL of $ENV{'PBPROJ'}: $pburl->{$ENV{'PBPROJ'}}\n");
69my ($scheme, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}});
70my $vcscmd = pb_vcs_cmd($scheme);
71
72my ($pbprojdir) = pb_conf_get_if("pbprojdir");
73
74if ((defined $pbprojdir) && (defined $pbprojdir->{$ENV{'PBPROJ'}})) {
75 $ENV{'PBPROJDIR'} = $pbprojdir->{$ENV{'PBPROJ'}};
76} else {
77 $ENV{'PBPROJDIR'} = "$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}";
78}
79# Expand potential env variable in it to allow string replacement
80eval { $ENV{'PBPROJDIR'} =~ s/(\$ENV.+\})/$1/eeg };
81
82
83# Computing the default dir for PBDIR.
84# what we have is PBPROJDIR so work from that.
85# Tree identical between PBCONFDIR and PBROOTDIR on one side and
86# PBPROJDIR and PBDIR on the other side.
87
88my $tmp = $ENV{'PBROOTDIR'};
89$tmp =~ s|^$ENV{'PBCONFDIR'}/||;
90
91#
92# Check project cms compliance
93#
94my $turl = "$pburl->{$ENV{'PBPROJ'}}/$tmp";
95$turl = $pburl->{$ENV{'PBPROJ'}} if ($scheme =~ /^(flat)|(ftp)|(http)|(file)\b/o);
96pb_cms_compliant(undef,'PBDIR',"$ENV{'PBPROJDIR'}/$tmp",$turl,$pbinit);
97
98
99if ($scheme =~ /^hg/) {
100 $tmp = `(cd "$ENV{'PBDIR'}" ; $vcscmd identify )`;
101 chomp($tmp);
102 $tmp =~ s/^.* //;
103 $ENV{'PBREVISION'}=$tmp;
104 $ENV{'PBCMSLOGFILE'}="hg.log";
105} elsif ($scheme =~ /^git/) {
106 if ($scheme =~ /svn/) {
107 $tmp = `(cd "$ENV{'PBDIR'}" ; LANGUAGE=C $vcscmd info | grep -E '^Revision:' | cut -d: -f2)`;
108 $tmp =~ s/\s+//;
109 } else {
110 $tmp = `(cd "$ENV{'PBDIR'}" ; $vcscmd log | head -1 | cut -f2)`;
111 $tmp =~ s/^.* //;
112 }
113 chomp($tmp);
114 $ENV{'PBREVISION'}=$tmp;
115 $ENV{'PBCMSLOGFILE'}="git.log";
116} elsif ($scheme =~ /^(flat)|(ftp)|(http)|(file)\b/o) {
117 $ENV{'PBREVISION'}="flat";
118 $ENV{'PBCMSLOGFILE'}="flat.log";
119} elsif ($scheme =~ /^svn/) {
120 # svnversion more precise than svn info if sbx
121 if ((defined $param) && ($param eq "CMS")) {
122 $tmp = `(LANGUAGE=C $vcscmd info $pburl->{$ENV{'PBPROJ'}} | grep -E '^Revision:' | cut -d: -f2)`;
123 $tmp =~ s/\s+//;
124 } else {
125 $tmp = `(cd "$ENV{'PBDIR'}" ; $vcscmd"version" .)`;
126 }
127 chomp($tmp);
128 $ENV{'PBREVISION'}=$tmp;
129 $ENV{'PBCMSLOGFILE'}="svn.log";
130} elsif ($scheme =~ /^svk/) {
131 $tmp = `(cd "$ENV{'PBDIR'}" ; LANGUAGE=C $vcscmd info . | grep -E '^Revision:' | cut -d: -f2)`;
132 $tmp =~ s/\s+//;
133 chomp($tmp);
134 $ENV{'PBREVISION'}=$tmp;
135 $ENV{'PBCMSLOGFILE'}="svk.log";
136} elsif ($scheme =~ /^cvs/) {
137 # Way too slow
138 #$ENV{'PBREVISION'}=`(cd "$ENV{'PBROOTDIR'}" ; cvs rannotate -f . 2>&1 | awk '{print \$1}' | grep -E '^[0-9]' | cut -d. -f2 |sort -nu | tail -1)`;
139 #chomp($ENV{'PBREVISION'});
140 $ENV{'PBREVISION'}="cvs";
141 $ENV{'PBCMSLOGFILE'}="cvs.log";
142 $ENV{'CVS_RSH'} = "ssh" if ($scheme =~ /ssh/);
143} else {
144 die "cms $scheme unknown";
145}
146
147pb_log(1,"pb_cms_init returns $scheme,$pburl->{$ENV{'PBPROJ'}}\n");
148return($scheme,$pburl->{$ENV{'PBPROJ'}});
149}
150
151=item B<pb_cms_checkin>
152
153This function updates a CMS content from a local directory.
154The first parameter is the schema of the CMS systems (svn, cvs, svn+ssh, ...)
155The second parameter is the directory to update from.
156The third parameter indicates if we are in a new version creation (undef) or in a new project creation (1)
157
158=cut
159
160sub pb_cms_checkin {
161my $scheme = shift;
162my $dir = shift;
163my $pbinit = shift || undef;
164
165my $ver = basename($dir);
166my $msg = "updated to $ver";
167$msg = "Project $ENV{'PBPROJ'} creation" if (defined $pbinit);
168
169pb_vcs_checkin($scheme,$dir,$msg);
170}
171
172=item B<pb_cms_get_pkg>
173
174This function returns the list of packages we are working on in a CMS action.
175The first parameter is the default list of packages from the configuration file.
176The second parameter is the optional list of packages from the configuration file.
177
178=cut
179
180sub pb_cms_get_pkg {
181
182my @pkgs = ();
183my $defpkgdir = shift || undef;
184my $extpkgdir = shift || undef;
185
186# Get packages list
187if (not defined $ARGV[0]) {
188 @pkgs = keys %$defpkgdir if (defined $defpkgdir);
189} elsif ($ARGV[0] =~ /^all$/) {
190 @pkgs = keys %$defpkgdir if (defined $defpkgdir);
191 push(@pkgs, keys %$extpkgdir) if (defined $extpkgdir);
192} else {
193 @pkgs = @ARGV;
194}
195pb_log(0,"Packages: ".join(',',@pkgs)."\n");
196return(\@pkgs);
197}
198
199=item B<pb_cms_get_real_pkg>
200
201This function returns the real name of a virtual package we are working on in a CMS action.
202It supports the following types: perl.
203The first parameter is the virtual package name
204
205=cut
206
207sub pb_cms_get_real_pkg {
208
209my $pbpkg = shift || undef;
210my $dtype = shift;
211my $pbpkgreal = $pbpkg;
212
213my @nametype = pb_conf_get_if("namingtype");
214my $type = $nametype[0]->{$pbpkg};
215if (defined $type) {
216 if ($type eq "perl") {
217 if ($dtype eq "rpm") {
218 $pbpkgreal = "perl-".$pbpkg;
219 } elsif ($dtype eq "deb") {
220 # Only lower case allowed in Debian
221 # Cf: http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Package
222 $pbpkgreal = "lib".lc($pbpkg)."-perl";
223 } elsif ($dtype eq "ebuild") {
224 $pbpkgreal = $pbpkg;
225 } elsif ($dtype eq "hpux") {
226 $pbpkgreal = $pbpkg;
227 } elsif ($dtype eq "pkg") {
228 $pbpkgreal = "PB$pbpkg";
229 } else {
230 die "pb_cms_get_real_pkg not implemented for $dtype yet";
231 }
232 } else {
233 die "nametype $type not implemented yet";
234 }
235}
236
237pb_log(2,"pb_cms_get_real_pkg returns $pbpkgreal\n");
238return($pbpkgreal);
239}
240
241=item B<pb_cms_compliant>
242
243This function checks the compliance of the project and the pbconf directory.
244The first parameter is the key name of the value that needs to be read in the configuration file.
245The second parameter is the environment variable this key will populate.
246The third parameter is the location of the pbconf dir.
247The fourth parameter is the URI of the CMS content related to the pbconf dir.
248The fifth parameter indicates whether we should inititate the context or not.
249
250=cut
251
252sub pb_cms_compliant {
253
254my $param = shift;
255my $envar = shift;
256my $defdir = shift;
257my $uri = shift;
258my $pbinit = shift;
259my %pdir;
260
261pb_log(1,"pb_cms_compliant: envar: $envar - defdir: $defdir - uri: $uri\n");
262my ($pdir) = pb_conf_get_if($param) if (defined $param);
263if (defined $pdir) {
264 %pdir = %$pdir;
265}
266
267
268if ((defined $pdir) && (%pdir) && (defined $pdir{$ENV{'PBPROJ'}})) {
269 # That's always the environment variable that will be used
270 $ENV{$envar} = $pdir{$ENV{'PBPROJ'}};
271} else {
272 if (defined $param) {
273 pb_log(1,"WARNING: no $param defined, using $defdir\n");
274 pb_log(1," Please create a $param reference for project $ENV{'PBPROJ'} in $ENV{'PBETC'}\n");
275 pb_log(1," if you want to use another directory\n");
276 }
277 $ENV{$envar} = "$defdir";
278}
279
280# Expand potential env variable in it
281eval { $ENV{$envar} =~ s/(\$ENV.+\})/$1/eeg };
282pb_log(2,"$envar: $ENV{$envar}\n");
283
284my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
285
286if (($scheme !~ /^cvs/) && ($scheme !~ /^svn/) && ($scheme !~ /^svk/) && ($scheme !~ /^hg/) && ($scheme !~ /^git/)) {
287 # Do not compare if it's not a real cms
288 pb_log(1,"pb_cms_compliant useless\n");
289 return;
290} elsif (defined $pbinit) {
291 pb_mkdir_p("$ENV{$envar}");
292} elsif (! -d "$ENV{$envar}") {
293 # Either we have a version in the uri, and it should be the same
294 # as the one in the envar. Or we should add the version to the uri
295 if (basename($uri) ne basename($ENV{$envar})) {
296 $uri .= "/".basename($ENV{$envar})
297 }
298 pb_log(1,"Checking out $uri\n");
299 # Create structure and remove end dir before exporting
300 pb_mkdir_p("$ENV{$envar}");
301 pb_rm_rf($ENV{$envar});
302 pb_vcs_checkout($scheme,$uri,$ENV{$envar});
303} else {
304 pb_log(1,"$uri found locally, checking content\n");
305 my $cmsurl = pb_vcs_get_uri($scheme,$ENV{$envar});
306 my ($scheme2, $account2, $host2, $port2, $path2) = pb_get_uri($cmsurl);
307 # For svk, scheme doesn't appear in svk info so remove it here in uri coming from conf file
308 # which needs it to trigger correct behaviour
309 $uri =~ s/^svk://;
310 if (($scheme2 =~ /^git/) || ($scheme2 =~ /^hg/)) {
311 # These VCS manage branches internally not with different tree structures
312 # Assuming it's correct for now.
313 } elsif ($cmsurl ne $uri) {
314 # The local content doesn't correpond to the repository
315 pb_log(0,"ERROR: Inconsistency detected:\n");
316 pb_log(0," * $ENV{$envar} ($envar) refers to $cmsurl but\n");
317 pb_log(0," * $ENV{'PBETC'} refers to $uri\n");
318 die "Project $ENV{'PBPROJ'} is not Project-Builder compliant.";
319 } else {
320 pb_log(1,"Content correct - doing nothing - you may want to update your repository however\n");
321 # they match - do nothing - there may be local changes
322 }
323}
324pb_log(1,"pb_cms_compliant end\n");
325}
326
327=item B<pb_cms_create_authors>
328
329This function creates a AUTHORS files for the project. It call it AUTHORS.pb if an AUTHORS file already exists.
330The first parameter is the source file for authors information.
331The second parameter is the directory where to create the final AUTHORS file.
332The third parameter is the schema of the CMS systems (svn, cvs, svn+ssh, ...)
333
334=cut
335
336sub pb_cms_create_authors {
337
338my $authors=shift;
339my $dest=shift;
340my $scheme=shift;
341
342return if ($authors eq "/dev/null");
343open(SAUTH,$authors) || die "Unable to open $authors";
344# Save a potentially existing AUTHORS file and write instead to AUTHORS.pb
345my $ext = "";
346if (-f "$dest/AUTHORS") {
347 $ext = ".pb";
348}
349open(DAUTH,"> $dest/AUTHORS$ext") || die "Unable to create $dest/AUTHORS$ext";
350print DAUTH "Authors of the project are:\n";
351print DAUTH "===========================\n";
352while (<SAUTH>) {
353 my ($nick,$gcos) = split(/:/);
354 chomp($gcos);
355 print DAUTH "$gcos";
356 if (defined $scheme) {
357 # Do not give a scheme for flat types
358 my $endstr="";
359 if ("$ENV{'PBREVISION'}" ne "flat") {
360 $endstr = " under $scheme";
361 }
362 print DAUTH " ($nick$endstr)\n";
363 } else {
364 print DAUTH "\n";
365 }
366}
367close(DAUTH);
368close(SAUTH);
369}
370
371=item B<pb_cms_log>
372
373This function creates a ChangeLog file for the project.
374The first parameter is the schema of the CMS systems (svn, cvs, svn+ssh, ...)
375The second parameter is the directory where the CMS content was checked out.
376The third parameter is the directory where to create the final ChangeLog file.
377The fourth parameter is unused.
378The fifth parameter is the source file for authors information.
379
380It may use a tool like svn2cl or cvs2cl to generate it if present, or the log file from the CMS if not.
381
382=cut
383
384
385sub pb_cms_log {
386
387my $scheme = shift;
388my $pkgdir = shift;
389my $dest = shift;
390my $chglog = shift;
391my $authors = shift;
392my $testver = shift || undef;
393
394pb_cms_create_authors($authors,$dest,$scheme);
395my $vcscmd = pb_vcs_cmd($scheme);
396
397if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) {
398 if (! -f "$dest/ChangeLog") {
399 open(CL,"> $dest/ChangeLog") || confess "Unable to create $dest/ChangeLog";
400 # We need a minimal version for debian type of build
401 print CL "\n";
402 print CL "\n";
403 print CL "\n";
404 print CL "\n";
405 print CL "1990-01-01 none\n";
406 print CL "\n";
407 print CL " * test version\n";
408 print CL "\n";
409 close(CL);
410 pb_log(0,"Generating fake ChangeLog for test version\n");
411 open(CL,"> $dest/$ENV{'PBCMSLOGFILE'}") || die "Unable to create $dest/$ENV{'PBCMSLOGFILE'}";
412 close(CL);
413 }
414}
415
416if (! -f "$dest/ChangeLog") {
417 if ($scheme =~ /^svn/) {
418 # In case we have no network, just create an empty one before to allow correct build
419 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
420 close(CL);
421 my $command = pb_check_req("svn2cl",1);
422 if ((defined $command) && (-x $command)) {
423 pb_system("$command --group-by-day --authors=$authors -i -o $dest/ChangeLog $pkgdir","Generating ChangeLog from SVN with svn2cl");
424 } else {
425 # To be written from pbcl
426 pb_system("$vcscmd log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from SVN");
427 }
428 } elsif ($scheme =~ /^svk/) {
429 pb_system("$vcscmd log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from SVK");
430 } elsif ($scheme =~ /^hg/) {
431 # In case we have no network, just create an empty one before to allow correct build
432 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
433 close(CL);
434 pb_system("$vcscmd log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from Mercurial");
435 } elsif ($scheme =~ /^git/) {
436 # In case we have no network, just create an empty one before to allow correct build
437 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
438 close(CL);
439 pb_system("$vcscmd log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from GIT");
440 } elsif ($scheme =~ /^(flat)|(ftp)|(http)|(file)|(dir)\b/o) {
441 pb_system("echo ChangeLog for $pkgdir > $dest/ChangeLog","Empty ChangeLog file created");
442 } elsif ($scheme =~ /^cvs/) {
443 my $tmp=basename($pkgdir);
444 # CVS needs a relative path !
445 # In case we have no network, just create an empty one before to allow correct build
446 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
447 close(CL);
448 my $command = pb_check_req("cvs2cl",1);
449 if (-x $command) {
450 pb_system("$command --group-by-day -U $authors -f $dest/ChangeLog $pkgdir","Generating ChangeLog from CVS with cvs2cl");
451 } else {
452 # To be written from pbcl
453 pb_system("$vcscmd log $tmp > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from CVS");
454 }
455 } else {
456 die "cms $scheme unknown";
457 }
458}
459if (! -f "$dest/ChangeLog") {
460 copy("$dest/$ENV{'PBCMSLOGFILE'}","$dest/ChangeLog");
461}
462}
463
464=back
465
466=head1 WEB SITES
467
468The 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/>.
469
470=head1 USER MAILING LIST
471
472None exists for the moment.
473
474=head1 AUTHORS
475
476The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
477
478=head1 COPYRIGHT
479
480Project-Builder.org is distributed under the GPL v2.0 license
481described in the file C<COPYING> included with the distribution.
482
483=cut
484
4851;
Note: See TracBrowser for help on using the repository browser.