This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add add-package.pl to the core (was Re: Why no (XML|DBI|WWW|Template) modules in...
[perl5.git] / Porting / add-package.pl
CommitLineData
28f2d4d1
JB
1#!/opt/bin/perl
2use strict;
3use warnings;
4
5use Cwd;
6use Getopt::Std;
7use File::Basename;
8use FindBin;
9
10my $Opts = {};
11getopts( 'r:p:e:vud', $Opts );
12
13my $Cwd = cwd();
14my $Verbose = 1;
15my $ExcludeRe = $Opts->{e} ? qr/$Opts->{e}/ : undef;
16my $Debug = $Opts->{v} || 0;
17my $RunDiff = $Opts->{d} || 0;
18my $PkgDir = $Opts->{p} || cwd();
19my $MasterRepo = $Opts->{r} or die "Need repository!\n". usage();
20
21### strip trailing slashes;
22$MasterRepo =~ s|/$||;
23
24my $CPV = $Debug ? '-v' : '';
25my $TestBin = 'ptardiff';
26my $PkgDirRe = quotemeta( $PkgDir .'/' );
27my $Repo = $MasterRepo . '-' . basename( $PkgDir ) . '.' . $$;
28
29### chdir there
30chdir $PkgDir or die "Could not chdir to $PkgDir: $!";
31
32### set up the repo dir from the master repo
33{ print "Setting up working repo under '$Repo'..." if $Verbose;
34 unless( -d $Repo ) {
35 system( "mkdir -p $Repo" )
36 and die "Could not create working repo '$Repo': $?";
37 }
38
39 system( "cp -Rf $MasterRepo/* $Repo" )
40 and die "Copying master repo to $Repo failed: $?";
41
42 print "done\n" if $Verbose;
43}
44
45### copy over all files under lib/
46{ print "Copying libdir..." if $Verbose;
47 die "No lib/ directory found\n" unless -d 'lib';
48 system( "cp -fR $CPV lib $Repo" ) and die "Copy of lib/ failed: $?";
49 print "done\n" if $Verbose;
50}
51
52### find the directory to put the t/ and bin/ files under
53my $RelTopDir; # topdir from the repo root
54my $TopDir; # full path to the top dir
55my $ModName; # name of the module
56my @ModFiles; # the .PMs in this package
57{ print "Creating top level dir..." if $Verbose;
58
59 ### make sure we get the shortest file, so we dont accidentally get
60 ### a subdir
61 @ModFiles = sort { length($a) <=> length($b) }
62 map { chomp; $_ }
63 grep { $ExcludeRe ? $_ !~ $ExcludeRe : 1 }
64 grep /\.p(?:m|od)$/,
65 `find $PkgDir/lib -type f`
66 or die "No TopDir detected\n";
67
68 $RelTopDir = $ModFiles[0];
69 $RelTopDir =~ s/^$PkgDirRe//;
70 $RelTopDir =~ s/\.p(m|od)$//;
71 $TopDir = "$Repo/$RelTopDir";
72
73 ### create the dir if it's not there yet
74 unless( -d $TopDir ) {
75 system( "mkdir $TopDir" ) and die "Creating dir $TopDir failed: $?";
76 }
77
78 ### the module name, like Foo::Bar
79 ### slice syntax not elegant, but we need to remove the
80 ### leading 'lib/' entry
81 ### stupid temp vars! stupid perl! it doesn't do @{..}[0..-1] :(
82 { my @list = @{[split '/', $RelTopDir]};
83 $ModName = join '::', @list[1 .. $#list];
84 }
85
86 ### the .pm files in this package
87 @ModFiles = map { s|^$PkgDirRe||; $_ } @ModFiles
88 or die "Could not detect modfiles\n";
89
90 print "done\n" if $Verbose;
91}
92
93my $TopDirRe = quotemeta( $TopDir . '/' );
94
95### copy over t/ and bin/ directories to the $TopDir
96my @TestFiles;
97{ print "Copying t/* files to $TopDir..." if $Verbose;
98
99 -d 't'
100 ? system( "cp -fR $CPV t $TopDir" ) && die "Copy of t/ failed: $?"
101 : warn "No t/ directory found\n";
102
103 @TestFiles = map { chomp; s|^$TopDirRe||; $_ }
104 ### should we get rid of this file?
105 grep { $ExcludeRe && $_ =~ $ExcludeRe
106 ? do { warn "Removing $_\n";
107 system("rm $_") and die "rm '$_' failed: $?";
108 undef
109 }
110 : 1
111 } `find $TopDir/t -type f`
112 or die "Could not detect testfiles\n";
113
114 print "done\n" if $Verbose;
115}
116
117my @BinFiles;
118BIN: {
119 unless (-d 'bin') {
120 print "No bin/ directory found\n" if $Verbose;
121 last BIN;
122 }
123 print "Copying bin/* files to $TopDir..." if $Verbose;
124
125 system("cp -fR $CPV bin/* $TopDir/bin/") && die "Copy of bin/ failed: $?";
126
127 @BinFiles = map { chomp; s|^$TopDirRe||; $_ }
128 ### should we get rid of this file?
129 grep { $ExcludeRe && $_ =~ $ExcludeRe
130 ? do { warn "Removing $_\n";
131 system("rm $_") and die "rm '$_' failed: $?";
132 undef
133 }
134 : 1
135 } `find $TopDir/bin -type f`
136 or die "Could not detect binfiles\n";
137
138 print "done\n" if $Verbose;
139}
140
141### add files where they are required
142my @NewFiles;
143{ for my $bin ( map { basename( $_ ) } @BinFiles ) {
144 print "Registering $bin with system files...\n";
145
146 ### fix installperl, so these files get installed by other utils
147 ### ./installperl: return if $name =~
148 ### /^(?:cpan|instmodsh|prove|corelist|ptar|ptardiff|config_data)\z/;
149 { my $file = 'installperl';
150
151 ### not there already?
152 unless( `grep $TestBin $Repo/$file| grep $bin` ) {
153 print " Adding $bin to $file..." if $Verbose;
154
155 ### double \\| required --> once for in this script, once
156 ### for the cli
157 system("$^X -pi -e 's/($TestBin\\|)/$bin|\$1/' $Repo/$file")
158 and die "Could not add $bin to $file: $?";
159 print "done\n" if $Verbose;
160 } else {
161 print " $bin already mentioned in $file\n" if $Verbose;
162 }
163 }
164
165 ### fix utils.lst, so the new tools are mentioned
166 { my $file = 'utils.lst';
167
168 ### not there already?
169 unless( `grep $bin $Repo/$file` ) {
170 print " Adding $bin to $file..." if $Verbose;
171
172 ### double \\| required --> once for in this script, once
173 ### for the cli
174 system("$^X -pi -e 's!($TestBin)!\$1\nutils/$bin!' $Repo/$file")
175 and die "Could not add $bin to $file: $?";
176 print "done\n" if $Verbose;
177 } else {
178 print " $bin already mentioned in $file\n" if $Verbose;
179 }
180 }
181
182 ### make a $bin.PL file and fix it up
183 { my $src = "utils/${TestBin}.PL";
184 my $file = "utils/${bin}.PL";
185
186 ### not there already?
187 unless( -e "$Repo/$file" ) {
188 print " Creating $file..." if $Verbose;
189
190 ### important part of the template looks like this
191 ### (we'll need to change it):
192 # my $script = File::Spec->catfile(
193 # File::Spec->catdir(
194 # File::Spec->updir, qw[lib Archive Tar bin]
195 # ), "module-load.pl");
196
197 ### copy another template file
198 system( "cp -f $Repo/$src $Repo/$file" )
199 and die "Could not create $file from $src: $?";
200
201 ### change the 'updir' path
202 ### make sure to escape the \[ character classes
203 my $updir = join ' ', (split('/', $RelTopDir), 'bin');
204 system( "$^X -pi -e'".
205 's/^(.*?File::Spec->updir, qw\[).+?(\].*)$/'.
206 "\$1 $updir \$2/' $Repo/$file"
207 ) and die "Could not fix updir for $bin in $file: $?";
208
209
210 ### change the name of the file from $TestBin to $bin
211 system( "$^X -pi -e's/$TestBin/$bin/' $Repo/$file" )
212 and die "Could not update $file with '$bin' as name: $?";
213
214 print "done\n" if $Verbose;
215
216 } else {
217 print " $file already exists\n" if $Verbose;
218 }
219
220 ### we've may just have created a new file, it will have to
221 ### go into the manifest
222 push @NewFiles, $file;
223 }
224
225 ### add an entry to utils/Makefile for $bin
226 { my $file = "utils/Makefile";
227
228 ### not there already?
229 unless( `grep $bin $Repo/$file` ) {
230 print " Adding $bin entries to $file..." if $Verbose;
231
232 ### $bin appears on 4 lines in this file, so replace all 4
233 ### first, pl =
234 system( "$^X -pi -e'/^pl\\s+=/ && s/(${TestBin}.PL)/".
235 "\$1 ${bin}.PL/' $Repo/$file"
236 ) and die "Could not add $bin to the pl = entry: $?";
237
238 ### next, plextract =
239 system( "$^X -pi -e'/^plextract\\s+=/ " .
240 "&& s/(${TestBin})/\$1 $bin/' $Repo/$file"
241 ) and die "Could not add $bin to the plextract = entry: $?";
242
243 ### third, plextractexe =
244 system( "$^X -pi -e'/^plextractexe\\s+=/ " .
245 "&& s!(\./${TestBin})!\$1 ./$bin!' $Repo/$file"
246 ) and die "Could not add $bin to the plextractexe = entry: $?";
247
248 ### last, the make directive $bin:
249 system( "$^X -pi -e'/^(${TestBin}:.+)/; \$x=\$1 or next;" .
250 "\$x =~ s/$TestBin/$bin/g;" . '$_.=$/.$x.$/;' .
251 "' $Repo/$file"
252 ) and die "Could not add $bin as a make directive: $?";
253
254 print "done\n" if $Verbose;
255 } else {
256 print " $bin already added to $file\n" if $Verbose;
257 }
258 }
259
260 ### add entries to win32/Makefile and win32/makefile.mk
261 ### they contain the following lines:
262 # ./win32/makefile.mk: ..\utils\ptardiff \
263 # ./win32/makefile.mk: xsubpp instmodsh prove ptar ptardiff
264 for my $file ( qw[win32/Makefile win32/makefile.mk] ) {
265 unless ( `grep $bin $Repo/$file` ) {
266 print " Adding $bin entries to $file..." if $Verbose;
267
268 system( "$^X -pi -e'/^(.+?utils.${TestBin}.+)/;".
269 '$x=$1 or next;' .
270 "\$x =~ s/$TestBin/$bin/g;" . '$_.=$x.$/;' .
271 "' $Repo/$file"
272 ) and die "Could not add $bin to UTILS section in $file: $?\n";
273
274 system( "$^X -pi -e's/( $TestBin)/\$1 $bin/' $Repo/$file" )
275 and die "Could not add $bin to $file: $?\n";
276
277 print "done\n" if $Verbose;
278 } else {
279 print " $bin already added to $file\n" if $Verbose;
280 }
281 }
282
283 ### we need some entries in a vms specific file as well..
284 ### except, i dont understand how it works or what it does, and it
285 ### looks all a bit odd... so lets just print a warning...
286 ### the entries look something like this:
287 # ./vms/descrip_mms.template:utils4 = [.utils]enc2xs.com
288 # [.utils]piconv.com [.utils]cpan.com [.utils]prove.com
289 # [.utils]ptar.com [.utils]ptardiff.com [.utils]shasum.com
290 # ./vms/descrip_mms.template:[.utils]ptardiff.com : [.utils]ptardiff.PL
291 # $(ARCHDIR)Config.pm
292 { my $file = 'vms/descrip_mms.template';
293
294 unless( `grep $bin $Repo/$file` ) {
295 print $/.$/;
296 print " WARNING! You should add entries like the following\n"
297 . " to $file (Using $TestBin as an example)\n"
298 . " Unfortunately I dont understand what these entries\n"
299 . " do, so I wont change them automatically:\n\n";
300
301 print `grep -nC1 $TestBin $Repo/$file`;
302 print $/.$/;
303
304 } else {
305 print " $bin already added to $file\n" if $Verbose;
306 }
307 }
308 }
309}
310
311### binary files must be encoded!
312### XXX use the new 'uupacktool.pl'
313{ my $pack = "$Repo/uupacktool.pl";
314
315 ### pack.pl encodes binary files for us
316 -e $pack or die "Need $pack to encode binary files!";
317
318 ### chdir, so uupacktool writes relative files properly
319 ### into it's header...
320 my $curdir = cwd();
321 chdir($Repo) or die "Could not chdir to '$Repo': $!";
322
323 for my $aref ( \@ModFiles, \@TestFiles, \@BinFiles ) {
324 for my $file ( @$aref ) {
325 my $full = -e $file ? $file :
326 -e "$RelTopDir/$file" ? "$RelTopDir/$file" :
327 die "Can not find $file in $Repo or $TopDir\n";
328
329 if( -f $full && -s _ && -B _ ) {
330 print "Binary file $file needs encoding\n" if $Verbose;
331
332 my $out = $full . '.packed';
333
334 ### does the file exist already?
335 ### and doesn't have +w
336 if( -e $out && not -w _ ) {
337 system("chmod +w $out")
338 and die "Could not set chmod +w to '$out': $!";
339 }
340
341 ### -D to remove the original
342 system("$^X $pack -D -p $full $out")
343 and die "Could not encode $full to $out";
344
345
346 $file .= '.packed';
347 }
348 }
349 }
350
351 chdir($curdir) or die "Could not chdir back to '$curdir': $!";
352}
353
354### update the manifest
355{ my $file = $Repo . '/MANIFEST';
356 my @manifest;
357 { open my $fh, "<$file" or die "Could not open $file: $!";
358 @manifest = <$fh>;
359 close $fh;
360 }
361
362 ### fill it with files from our package
363 my %pkg_files;
364 for ( @ModFiles ) {
365 $pkg_files{$_} = "$_\t$ModName\n";
366 }
367
368 for ( @TestFiles ) {
369 $pkg_files{"$RelTopDir/$_"} = "$RelTopDir/$_\t$ModName tests\n"
370 }
371
372 for ( @BinFiles ) {
373 $pkg_files{"$RelTopDir/$_"} = "$RelTopDir/$_\tthe ".
374 basename($_) ." utility\n";
375 }
376
377 for ( @NewFiles ) {
378 $pkg_files{$_} = "$_\tthe ".
379 do { m/(.+?)\.PL$/; basename($1) } .
380 " utility\n"
381 }
382
383 ### remove all the files that are already in the manifest;
384 delete $pkg_files{ [split]->[0] } for @manifest;
385
386 print "Adding the following entries to the MANIFEST:\n" if $Verbose;
387 print "\t$_" for sort values %pkg_files;
388 print $/.$/;
389
390 push @manifest, values %pkg_files;
391
392 { chmod 0755, $file;
393 open my $fh, ">$file" or die "Could not open $file for writing: $!";
394 #print $fh sort { lc $a cmp lc $b } @manifest;
395 ### XXX stolen from pod/buildtoc:sub do_manifest
396 print $fh
397 map { $_->[0] }
398 sort { $a->[1] cmp $b->[1] || $a->[0] cmp $b->[0] }
399 map { my $f = lc $_; $f =~ s/[^a-z0-9\s]//g; [ $_, $f ] }
400 @manifest;
401
402 close $fh;
403 }
404}
405
406### would you like us to show you a diff?
407if( $RunDiff ) {
408 my $diff = $Repo; $diff =~ s/$$/patch/;
409
410 print "Generating diff..." if $Verbose;
411
412 ### weird RV ;(
413 my $master = basename( $MasterRepo );
414 my $repo = basename( $Repo );
415 my $chdir = dirname( $MasterRepo );
416
417 system( "cd $chdir; diff -ruN $master $repo > $diff" );
418 #and die "Could not write diff to '$diff': $?";
419 die "Could not write diff to '$diff'" unless -e $diff && -s _;
420
421 print "done\n" if $Verbose;
422 print "\nDiff can be applied with patch -p1 in $MasterRepo\n\n";
423 print " Diff written to: $diff\n\n" if $Verbose;
424}
425
426sub usage {
427 my $me = basename($0);
428 return qq[
429
430Usage: $me -r PERL_REPO_DIR [-p PACKAGE_DIR] [-v] [-d] [-e REGEX]
431
432Options:
433 -r Path to perl-core repository
434 -v Run verbosely
435 -e Perl regex matching files that shouldn't be included
436 -d Create a diff as patch file
437 -p Path to the package to add. Defaults to cwd()
438
439 \n];
440
441}