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

Last change on this file since 405 was 405, checked in by Bruno Cornec, 16 years ago

Split again function in modules to allow for usage with pbinit and easier reuse.

  • Property svn:executable set to *
File size: 12.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
10# Provided under the GPL v2
11
12package ProjectBuilder::CMS;
13
14use strict 'vars';
15use Data::Dumper;
16use English;
17use File::Basename;
18use POSIX qw(strftime);
19use lib qw (lib);
20use ProjectBuilder::Base;
21use ProjectBuilder::Conf;
22
23# Inherit from the "Exporter" module which handles exporting functions.
24
25use Exporter;
26
27# Export, by default, all the functions into the namespace of
28# any code which uses this module.
29
30our @ISA = qw(Exporter);
31our @EXPORT = qw(pb_cms_init pb_cms_export pb_cms_get_uri pb_cms_copy pb_cms_checkout pb_cms_up pb_cms_checkin pb_cms_isdiff pb_cms_get_pkg pb_cms_compliant pb_cms_log pb_cms_create_authors);
32
33=pod
34
35=head1 NAME
36
37ProjectBuilder::CMS, part of the project-builder.org - module dealing with configuration management system functions suitable for pbinit calls.
38
39=head1 DESCRIPTION
40
41This modules provides configuration management system functions suitable for pbinit calls.
42
43=cut
44
45# Setup environment for CMS system for URL passed
46sub pb_cms_init {
47
48my $pbinit = shift || undef;
49
50my ($pburl) = pb_conf_get("pburl");
51pb_log(2,"DEBUG: Project URL of $ENV{'PBPROJ'}: $pburl->{$ENV{'PBPROJ'}}\n");
52my ($scheme, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}});
53
54my ($pbprojdir) = pb_conf_get_if("pbprojdir");
55
56if ((defined $pbprojdir) && (defined $pbprojdir->{$ENV{'PBPROJ'}})) {
57 $ENV{'PBPROJDIR'} = $pbprojdir->{$ENV{'PBPROJ'}};
58} else {
59 $ENV{'PBPROJDIR'} = "$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}";
60}
61
62# Computing the default dir for PBDIR.
63# what we have is PBPROJDIR so work from that.
64# Tree identical between PBCONFDIR and PBROOTDIR on one side and
65# PBPROJDIR and PBDIR on the other side.
66
67my $tmp = $ENV{'PBROOTDIR'};
68$tmp =~ s|^$ENV{'PBCONFDIR'}||;
69
70#
71# Check project cms compliance
72#
73pb_cms_compliant(undef,'PBDIR',"$ENV{'PBPROJDIR'}/$tmp",$pburl->{$ENV{'PBPROJ'}},$pbinit);
74
75if ($scheme =~ /^svn/) {
76 # svnversion more precise than svn info
77 $tmp = `(cd "$ENV{'PBDIR'}" ; svnversion .)`;
78 chomp($tmp);
79 $ENV{'PBREVISION'}=$tmp;
80 $ENV{'PBCMSLOGFILE'}="svn.log";
81} elsif (($scheme eq "file") || ($scheme eq "ftp") || ($scheme eq "http")) {
82 $ENV{'PBREVISION'}="flat";
83 $ENV{'PBCMSLOGFILE'}="flat.log";
84} elsif ($scheme =~ /^cvs/) {
85 # Way too slow
86 #$ENV{'PBREVISION'}=`(cd "$ENV{'PBROOTDIR'}" ; cvs rannotate -f . 2>&1 | awk '{print \$1}' | grep -E '^[0-9]' | cut -d. -f2 |sort -nu | tail -1)`;
87 #chomp($ENV{'PBREVISION'});
88 $ENV{'PBREVISION'}="cvs";
89 $ENV{'PBCMSLOGFILE'}="cvs.log";
90 $ENV{'CVS_RSH'} = "ssh" if ($scheme =~ /ssh/);
91} else {
92 die "cms $scheme unknown";
93}
94
95return($scheme,$pburl->{$ENV{'PBPROJ'}});
96}
97
98sub pb_cms_export {
99
100my $uri = shift;
101my $source = shift;
102my $destdir = shift;
103my $tmp;
104my $tmp1;
105
106my @date = pb_get_date();
107# If it's not flat, then we have a real uri as source
108my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
109
110if ($scheme =~ /^svn/) {
111 if (-d $source) {
112 $tmp = $destdir;
113 } else {
114 $tmp = "$destdir/".basename($source);
115 }
116 pb_system("svn export $source $tmp","Exporting $source from SVN to $tmp");
117} elsif ($scheme eq "dir") {
118 pb_system("cp -a $path $destdir","Copying $uri from DIR to $destdir");
119} elsif (($scheme eq "http") || ($scheme eq "ftp")) {
120 my $f = basename($path);
121 unlink "$ENV{'PBTMP'}/$f";
122 if (-x "/usr/bin/wget") {
123 pb_system("/usr/bin/wget -nv -O $ENV{'PBTMP'}/$f $uri"," ");
124 } elsif (-x "/usr/bin/curl") {
125 pb_system("/usr/bin/curl $uri -o $ENV{'PBTMP'}/$f","Downloading $uri with curl to $ENV{'PBTMP'}/$f\n");
126 } else {
127 die "Unable to download $uri.\nNo wget/curl available, please install one of those";
128 }
129 pb_cms_export("file://$ENV{'PBTMP'}/$f",$source,$destdir);
130} elsif ($scheme eq "file") {
131 use File::MimeInfo;
132 my $mm = mimetype($path);
133 pb_log(2,"mimetype: $mm\n");
134 pb_mkdir_p($destdir);
135
136 # Check whether the file is well formed
137 # (containing already a directory with the project-version name)
138 my ($pbwf) = pb_conf_get_if("pbwf");
139 if ((defined $pbwf) && (defined $pbwf->{$ENV{'PBPROJ'}})) {
140 $destdir = dirname($destdir);
141 }
142
143 if ($mm =~ /\/x-bzip-compressed-tar$/) {
144 # tar+bzip2
145 pb_system("cd $destdir ; tar xfj $path","Extracting $path in $destdir");
146 } elsif ($mm =~ /\/x-lzma-compressed-tar$/) {
147 # tar+lzma
148 pb_system("cd $destdir ; tar xfY $path","Extracting $path in $destdir");
149 } elsif ($mm =~ /\/x-compressed-tar$/) {
150 # tar+gzip
151 pb_system("cd $destdir ; tar xfz $path","Extracting $path in $destdir");
152 } elsif ($mm =~ /\/x-tar$/) {
153 # tar
154 pb_system("cd $destdir ; tar xf $path","Extracting $path in $destdir");
155 } elsif ($mm =~ /\/zip$/) {
156 # zip
157 pb_system("cd $destdir ; unzip $path","Extracting $path in $destdir");
158 }
159} elsif ($scheme =~ /^cvs/) {
160 # CVS needs a relative path !
161 my $dir=dirname($destdir);
162 my $base=basename($destdir);
163 # CVS also needs a modules name not a dir
164 #if (-d $source) {
165 $tmp1 = basename($source);
166 #} else {
167 #$tmp1 = dirname($source);
168 #$tmp1 = basename($tmp1);
169 #}
170 my $optcvs = "";
171
172 # If we're working on the CVS itself
173 my $cvstag = basename($ENV{'PBROOTDIR'});
174 my $cvsopt = "";
175 if ($cvstag eq "cvs") {
176 my $pbdate = strftime("%Y-%m-%d %H:%M:%S", @date);
177 $cvsopt = "-D \"$pbdate\"";
178 } else {
179 # we're working on a tag which should be the last part of PBROOTDIR
180 $cvsopt = "-r $cvstag";
181 }
182 pb_system("cd $dir ; cvs -d $account\@$host:$path export $cvsopt -d $base $tmp1","Exporting $tmp1 from $source under CVS to $destdir");
183} else {
184 die "cms $scheme unknown";
185}
186}
187
188# This function is only called with a real CMS system
189sub pb_cms_get_uri {
190
191my $scheme = shift;
192my $dir = shift;
193
194my $res = "";
195my $void = "";
196
197if ($scheme =~ /^svn/) {
198 open(PIPE,"LANGUAGE=C svn info $dir |") || return("");
199 while (<PIPE>) {
200 ($void,$res) = split(/^URL:/) if (/^URL:/);
201 }
202 $res =~ s/^\s*//;
203 close(PIPE);
204 chomp($res);
205} elsif ($scheme =~ /^cvs/) {
206 # This path is always the root path of CVS, but we may be below
207 open(FILE,"$dir/CVS/Root") || die "$dir isn't CVS controlled";
208 $res = <FILE>;
209 chomp($res);
210 close(FILE);
211 # Find where we are in the tree
212 my $rdir = $dir;
213 while ((! -d "$rdir/CVSROOT") && ($rdir ne "/")) {
214 $rdir = dirname($rdir);
215 }
216 die "Unable to find a CVSROOT dir in the parents of $dir" if (! -d "$rdir/CVSROOT");
217 #compute our place under that root dir - should be a relative path
218 $dir =~ s|^$rdir||;
219 my $suffix = "";
220 $suffix = "$dir" if ($dir ne "");
221
222 my $prefix = "";
223 if ($scheme =~ /ssh/) {
224 $prefix = "cvs+ssh://";
225 } else {
226 $prefix = "cvs://";
227 }
228 $res = $prefix.$res.$suffix;
229} else {
230 die "cms $scheme unknown";
231}
232pb_log(2,"Found CMS info: $res\n");
233return($res);
234}
235
236sub pb_cms_copy {
237my $scheme = shift;
238my $oldurl = shift;
239my $newurl = shift;
240
241if ($scheme =~ /^svn/) {
242 pb_system("svn copy -m \"Creation of $newurl from $oldurl\" $oldurl $newurl","Copying $oldurl to $newurl ");
243} elsif ($scheme eq "flat") {
244} elsif ($scheme =~ /^cvs/) {
245} else {
246 die "cms $scheme unknown";
247}
248}
249
250sub pb_cms_checkout {
251my $scheme = shift;
252my $url = shift;
253my $destination = shift;
254
255if ($scheme =~ /^svn/) {
256 pb_system("svn co $url $destination","Checking out $url to $destination ");
257} elsif (($scheme eq "ftp") || ($scheme eq "http")) {
258 return;
259} elsif ($scheme =~ /^cvs/) {
260 pb_system("cvs co $url $destination","Checking out $url to $destination ");
261} else {
262 die "cms $scheme unknown";
263}
264}
265
266sub pb_cms_up {
267my $scheme = shift;
268my $dir = shift;
269
270if ($scheme =~ /^svn/) {
271 pb_system("svn up $dir","Updating $dir");
272} elsif ($scheme eq "flat") {
273} elsif ($scheme =~ /^cvs/) {
274} else {
275 die "cms $scheme unknown";
276}
277}
278
279sub pb_cms_checkin {
280my $scheme = shift;
281my $dir = shift;
282
283my $ver = basename($dir);
284if ($scheme =~ /^svn/) {
285 pb_system("svn ci -m \"updated to $ver\" $dir","Checking in $dir");
286} elsif ($scheme eq "flat") {
287} elsif ($scheme =~ /^cvs/) {
288} else {
289 die "cms $scheme unknown";
290}
291pb_cms_up($scheme,$dir);
292}
293
294sub pb_cms_isdiff {
295my $scheme = shift;
296my $dir =shift;
297
298if ($scheme =~ /^svn/) {
299 open(PIPE,"svn diff $dir |") || die "Unable to get svn diff from $dir";
300 my $l = 0;
301 while (<PIPE>) {
302 $l++;
303 }
304 return($l);
305} elsif ($scheme eq "flat") {
306} elsif ($scheme =~ /^cvs/) {
307 open(PIPE,"cvs diff $dir |") || die "Unable to get svn diff from $dir";
308 my $l = 0;
309 while (<PIPE>) {
310 # Skipping normal messages
311 next if (/^cvs diff:/);
312 $l++;
313 }
314 return($l);
315} else {
316 die "cms $scheme unknown";
317}
318}
319
320#
321# Return the list of packages we are working on in a CMS action
322#
323sub pb_cms_get_pkg {
324
325my @pkgs = ();
326my $defpkgdir = shift || undef;
327my $extpkgdir = shift || undef;
328
329# Get packages list
330if (not defined $ARGV[0]) {
331 @pkgs = keys %$defpkgdir if (defined $defpkgdir);
332} elsif ($ARGV[0] =~ /^all$/) {
333 @pkgs = keys %$defpkgdir if (defined $defpkgdir);
334 push(@pkgs, keys %$extpkgdir) if (defined $extpkgdir);
335} else {
336 @pkgs = @ARGV;
337}
338pb_log(0,"Packages: ".join(',',@pkgs)."\n");
339return(\@pkgs);
340}
341
342#
343# Check pbconf/project cms compliance
344#
345sub pb_cms_compliant {
346
347my $param = shift;
348my $envar = shift;
349my $defdir = shift;
350my $uri = shift;
351my $pbinit = shift;
352my %pdir;
353
354my ($pdir) = pb_conf_get_if($param) if (defined $param);
355if (defined $pdir) {
356 %pdir = %$pdir;
357}
358
359
360if ((defined $pdir) && (%pdir) && (defined $pdir{$ENV{'PBPROJ'}})) {
361 # That's always the environment variable that will be used
362 $ENV{$envar} = $pdir{$ENV{'PBPROJ'}};
363} else {
364 if (defined $param) {
365 pb_log(1,"WARNING: no $param defined, using $defdir\n");
366 pb_log(1," Please create a $param reference for project $ENV{'PBPROJ'} in $ENV{'PBETC'}\n");
367 pb_log(1," if you want to use another directory\n");
368 }
369 $ENV{$envar} = "$defdir";
370}
371
372# Expand potential env variable in it
373eval { $ENV{$envar} =~ s/(\$ENV.+\})/$1/eeg };
374pb_log(2,"$envar: $ENV{$envar}\n");
375
376my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri);
377
378if ((! -d "$ENV{$envar}") || (defined $pbinit)) {
379 if (defined $pbinit) {
380 pb_mkdir_p("$ENV{$envar}");
381 } else {
382 pb_log(1,"Checking out $uri\n");
383 pb_cms_checkout($scheme,$uri,$ENV{$envar});
384 }
385} elsif (($scheme !~ /^cvs/) || ($scheme !~ /^svn/)) {
386 # Do not compare if it's not a real cms
387 return;
388} else {
389 pb_log(1,"$uri found locally, checking content\n");
390 my $cmsurl = pb_cms_get_uri($scheme,$ENV{$envar});
391 my ($scheme2, $account2, $host2, $port2, $path2) = pb_get_uri($cmsurl);
392 if ($cmsurl ne $uri) {
393 # The local content doesn't correpond to the repository
394 pb_log(0,"ERROR: Inconsistency detected:\n");
395 pb_log(0," * $ENV{$envar} refers to $cmsurl but\n");
396 pb_log(0," * $ENV{'PBETC'} refers to $uri\n");
397 die "Project $ENV{'PBPROJ'} is not Project-Builder compliant.";
398 } else {
399 pb_log(1,"Content correct - doing nothing - you may want to update your repository however\n");
400 # they match - do nothing - there may be local changes
401 }
402}
403}
404
405sub pb_cms_create_authors {
406
407my $authors=shift;
408my $dest=shift;
409my $scheme=shift;
410
411return if ($authors eq "/dev/null");
412open(SAUTH,$authors) || die "Unable to open $authors";
413# Save a potentially existing AUTHORS file and write instead toi AUTHORS.pb
414my $ext = "";
415if (-f "$dest/AUTHORS") {
416 $ext = ".pb";
417}
418open(DAUTH,"> $dest/AUTHORS$ext") || die "Unable to create $dest/AUTHORS$ext";
419print DAUTH "Authors of the project are:\n";
420print DAUTH "===========================\n";
421while (<SAUTH>) {
422 my ($nick,$gcos) = split(/:/);
423 chomp($gcos);
424 print DAUTH "$gcos";
425 if (defined $scheme) {
426 # Do not give a scheme for flat types
427 my $endstr="";
428 if ("$ENV{'PBREVISION'}" ne "flat") {
429 $endstr = " under $scheme";
430 }
431 print DAUTH " ($nick$endstr)\n";
432 } else {
433 print DAUTH "\n";
434 }
435}
436close(DAUTH);
437close(SAUTH);
438}
439
440sub pb_cms_log {
441
442my $scheme = shift;
443my $pkgdir = shift;
444my $dest = shift;
445my $chglog = shift;
446my $authors = shift;
447
448pb_cms_create_authors($authors,$dest,$scheme);
449
450if ($scheme =~ /^svn/) {
451 if (! -f "$dest/ChangeLog") {
452 if (-x "/usr/bin/svn2cl") {
453 # In case we have no network, just create an empty one before to allow correct build
454 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
455 close(CL);
456 pb_system("/usr/bin/svn2cl --group-by-day --authors=$authors -i -o $dest/ChangeLog $pkgdir","Generating ChangeLog from SVN with svn2cl");
457 } else {
458 # To be written from pbcl
459 pb_system("svn log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from SVN");
460 }
461 }
462} elsif (($scheme eq "file") || ($scheme eq "dir") || ($scheme eq "http") || ($scheme eq "ftp")) {
463 if (! -f "$dest/ChangeLog") {
464 pb_system("echo ChangeLog for $pkgdir > $dest/ChangeLog","Empty ChangeLog file created");
465 }
466} elsif ($scheme =~ /^cvs/) {
467 my $tmp=basename($pkgdir);
468 # CVS needs a relative path !
469 if (! -f "$dest/ChangeLog") {
470 if (-x "/usr/bin/cvs2cl") {
471 # In case we have no network, just create an empty one before to allow correct build
472 open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog";
473 close(CL);
474 pb_system("/usr/bin/cvs2cl --group-by-day -U $authors -f $dest/ChangeLog $pkgdir","Generating ChangeLog from CVS with cvs2cl");
475 } else {
476 # To be written from pbcl
477 pb_system("cvs log $tmp > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from CVS");
478 }
479 }
480} else {
481 die "cms $scheme unknown";
482}
483}
484
4851;
Note: See TracBrowser for help on using the repository browser.