Generate lib/.gitignore from MANIFEST.
authorNicholas Clark <nick@ccl4.org>
Sat, 20 Jul 2013 10:50:21 +0000 (12:50 +0200)
committerNicholas Clark <nick@ccl4.org>
Wed, 24 Jul 2013 07:36:11 +0000 (09:36 +0200)
It's possible to programmatically determine almost all the files and
directories which will be created in lib/ by building the extensions.
Hence add a new script regen/lib_cleanup.pl to do this.

This saves having to manually update lib/.gitignore to reflect changes in
the build products of extensions, which has become a small but reoccurring
instance of scut-work.

MANIFEST
lib/.gitignore
regen/lib_cleanup.pl [new file with mode: 0644]

index a128a43..e7e153c 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -4763,6 +4763,7 @@ regen/embed.pl                    Produces {embed,embedvar,proto}.h
 regen/feature.pl               Generates feature.pm
 regen/genpacksizetables.pl     Generate the size tables for pack/unpack
 regen/keywords.pl              Program to write keywords.h
+regen/lib_cleanup.pl           Generate lib/.gitignore from MANIFEST
 regen/mg_vtable.pl             generate mg_vtable.h
 regen/miniperlmain.pl          generate miniperlmain.c
 regen/mk_invlists.pl           Generates charclass_invlists.h
index c4f79d5..8337da0 100644 (file)
@@ -1,7 +1,15 @@
+# -*- buffer-read-only: t -*-
+# !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
+# This file is built by regen/lib_cleanup.pl from MANIFEST and parsing files
+# in cpan/ dist/ and ext/.
+# Any changes made here will be lost!
+
+# If this generated file has problems, it may be simpler to add more special
+# cases to the top level .gitignore than to code one-off logic into the
+# generation script regen/lib_cleanup.pl
+
 /App/
-/Archive/Tar.pm
-/Archive/Tar/Constant.pm
-/Archive/Tar/File.pm
+/Archive/
 /Attribute/
 /AutoLoader.pm
 /AutoSplit.pm
 /CGI/
 /CPAN.pm
 /CPAN/
-/CPAN/API/
-/CPAN/API/HOWTO.pod
-/CPAN/Author.pm
-/CPAN/Bundle.pm
-/CPAN/CacheMgr.pm
-/CPAN/Complete.pm
-/CPAN/Debug.pm
-/CPAN/DeferredCode.pm
-/CPAN/Distribution.pm
-/CPAN/Distroprefs.pm
-/CPAN/Distrostatus.pm
-/CPAN/Exception/
-/CPAN/Exception/RecursiveDependency.pm
-/CPAN/Exception/blocked_urllist.pm
-/CPAN/Exception/yaml_not_installed.pm
-/CPAN/FTP.pm
-/CPAN/FTP/
-/CPAN/FTP/netrc.pm
-/CPAN/FirstTime.pm
-/CPAN/HandleConfig.pm
-/CPAN/Index.pm
-/CPAN/InfoObj.pm
-/CPAN/Kwalify.pm
-/CPAN/Kwalify/
-/CPAN/Kwalify/distroprefs.dd
-/CPAN/Kwalify/distroprefs.yml
-/CPAN/LWP/
-/CPAN/LWP/UserAgent.pm
-/CPAN/Meta.pm
-/CPAN/Meta/
-/CPAN/Module.pm
-/CPAN/Nox.pm
-/CPAN/PAUSE2003.pub
-/CPAN/PAUSE2005.pub
-/CPAN/PAUSE2007.pub
-/CPAN/PAUSE2009.pub
-/CPAN/Prompt.pm
-/CPAN/Queue.pm
-/CPAN/SIGNATURE/
-/CPAN/Shell.pm
-/CPAN/Tarzip.pm
-/CPAN/URL.pm
-/CPAN/Version.pm
 /Carp.pm
-/Carp/Heavy.pm
+/Carp/
 /Compress/
 /Config/Perl/
-/Config/Perl/V.pm
 /Cwd.pm
 /DB_File.pm
 /Data/
-/Devel/DProf.pm
-/Devel/DProf/
-/Devel/InnerPackage.pm
-/Devel/PPPort.pm
-/Devel/Peek.pm
-/Devel/SelfStubber.pm
+/Devel/
 /Digest.pm
-/Digest/MD5.pm
-/Digest/SHA.pm
-/Digest/base.pm
-/Digest/file.pm
+/Digest/
 /Dumpvalue.pm
 /DynaLoader.pm
 /Encode.pm
 /Env.pm
 /Errno.pm
 /Exporter.pm
-/Exporter/Heavy.pm
+/Exporter/
 /ExtUtils/CBuilder.pm
 /ExtUtils/CBuilder/
 /ExtUtils/Command.pm
-/ExtUtils/Command/MM.pm
+/ExtUtils/Command/
 /ExtUtils/Constant.pm
 /ExtUtils/Constant/
 /ExtUtils/Install.pm
 /ExtUtils/Installed.pm
 /ExtUtils/Liblist.pm
-/ExtUtils/Liblist/Kid.pm
+/ExtUtils/Liblist/
 /ExtUtils/MM.pm
 /ExtUtils/MM_AIX.pm
 /ExtUtils/MM_Any.pm
 /ExtUtils/MM_Win95.pm
 /ExtUtils/MY.pm
 /ExtUtils/MakeMaker.pm
-/ExtUtils/MakeMaker/Config.pm
-/ExtUtils/MakeMaker/FAQ.pod
-/ExtUtils/MakeMaker/Tutorial.pod
-/ExtUtils/MakeMaker/YAML.pm
+/ExtUtils/MakeMaker/
 /ExtUtils/Manifest.pm
 /ExtUtils/Miniperl.pm
 /ExtUtils/Mkbootstrap.pm
 /ExtUtils/Mksymlists.pm
+/ExtUtils/Myconst2perl.pm
 /ExtUtils/Packlist.pm
 /ExtUtils/ParseXS.pm
 /ExtUtils/ParseXS.pod
 /ExtUtils/Typemaps.pm
 /ExtUtils/Typemaps/
 /ExtUtils/testlib.pm
-/ExtUtils/xsubpp
 /Fatal.pm
 /Fcntl.pm
-/File/CheckTree.pm
 /File/DosGlob.pm
 /File/Fetch.pm
 /File/Find.pm
 /File/Spec/
 /File/Temp.pm
 /FileCache.pm
-/Filter/Simple.pm
-/Filter/Util/
+/Filter/
 /GDBM_File.pm
 /Getopt/Long.pm
-/HTTP/Tiny.pm
+/HTTP/
 /Hash/
-/I18N/Collate.pm
-/I18N/LangTags.pm
-/I18N/LangTags/
-/I18N/Langinfo.pm
+/I18N/
 /IO.pm
-/IO/Compress/
-/IO/Dir.pm
-/IO/File.pm
-/IO/Handle.pm
-/IO/Pipe.pm
-/IO/Poll.pm
-/IO/Seekable.pm
-/IO/Select.pm
-/IO/Socket.pm
-/IO/Socket/
-/IO/Uncompress/
-/IO/Zlib.pm
-/IPC/Cmd.pm
-/IPC/Msg.pm
-/IPC/Open2.pm
-/IPC/Open3.pm
-/IPC/Semaphore.pm
-/IPC/SharedMem.pm
-/IPC/SysV.pm
-/JSON/PP.pm
-/JSON/PP/Boolean.pm
+/IO/
+/IPC/
+/JSON/
 /List/
 /Locale/
-/Locale/Constants.pm
-/Locale/Constants.pod
-/Locale/Country.pm
-/Locale/Country.pod
-/Locale/Currency.pm
-/Locale/Currency.pod
-/Locale/Language.pm
-/Locale/Language.pod
-/Locale/Maketext.pm
-/Locale/Maketext.pod
-/Locale/Maketext/
-/Locale/Maketext/Guts.pm
-/Locale/Maketext/GutsLoader.pm
-/Locale/Maketext/Simple.pm
-/Locale/Maketext/TPJ13.pod
-/Locale/Script.pm
-/Locale/Script.pod
 /MIME/
 /Math/
-/Math/BigFloat.pm
-/Math/BigFloat/
-/Math/BigFloat/Trace.pm
-/Math/BigInt.pm
-/Math/BigInt/
-/Math/BigInt/Calc.pm
-/Math/BigInt/CalcEmu.pm
-/Math/BigInt/FastCalc.pm
-/Math/BigInt/Trace.pm
-/Math/BigRat.pm
-/Math/Complex.pm
-/Math/Trig.pm
 /Memoize.pm
 /Memoize/
-/Memoize/AnyDBM_File.pm
-/Memoize/Expire.pm
-/Memoize/ExpireFile.pm
-/Memoize/ExpireTest.pm
-/Memoize/NDBM_File.pm
-/Memoize/SDBM_File.pm
-/Memoize/Storable.pm
-/Module/Build.pm
-/Module/Build/
-/Module/CoreList.pm
-/Module/CoreList.pod
-/Module/CoreList/
-/Module/CoreList/TieHashDelta.pm
-/Module/Load.pm
-/Module/Load/Conditional.pm
-/Module/Loaded.pm
-/Module/Metadata.pm
+/Module/
 /NDBM_File.pm
 /NEXT.pm
 /Net/Cmd.pm
 /Net/Domain.pm
 /Net/FTP.pm
 /Net/FTP/
-/Net/FTP/A.pm
-/Net/FTP/E.pm
-/Net/FTP/I.pm
-/Net/FTP/L.pm
-/Net/FTP/dataconn.pm
 /Net/NNTP.pm
 /Net/Netrc.pm
 /Net/POP3.pm
 /Opcode.pm
 /POSIX.pm
 /POSIX.pod
-/Package/Constants.pm
-/Params/Check.pm
-/Parse/CPAN/
-/Perl/OSType.pm
-/PerlIO/encoding.pm
-/PerlIO/mmap.pm
-/PerlIO/scalar.pm
-/PerlIO/via.pm
-/PerlIO/via/QuotedPrint.pm
+/Package/
+/Params/
+/Parse/
+/Perl/
+/PerlIO/
 /Pod/Checker.pm
 /Pod/Escapes.pm
 /Pod/Find.pm
 /Pod/Simple.pm
 /Pod/Simple.pod
 /Pod/Simple/
-/Pod/Simple/t/corpus/2202jp.txt
-/Pod/Simple/t/corpus/2202jpx.txt
-/Pod/Simple/t/corpus/2202jpy.txt
-/Pod/Simple/t/corpus2/polish_utf16be_bom.txt
-/Pod/Simple/t/corpus2/polish_utf16le_bom.txt
 /Pod/Text.pm
 /Pod/Text/
 /Pod/Usage.pm
 /Term/
 /Test.pm
 /Test/
-/Test/Builder.pm
-/Test/Builder/
-/Test/More.pm
-/Test/Simple.pm
-/Test/Tutorial.pod
-/Text/Abbrev.pm
-/Text/Balanced.pm
-/Text/ParseWords.pm
-/Text/Soundex.pm
-/Text/Tabs.pm
-/Text/Wrap.pm
+/Text/
 /Thread/
 /Tie/File.pm
-/Tie/Hash/NamedCapture.pm
+/Tie/Hash/
 /Tie/Memoize.pm
 /Tie/RefHash.pm
 /Time/HiRes.pm
 /Unicode/Collate.pm
 /Unicode/Collate/
 /Unicode/Normalize.pm
+/VMS/
 /Win32.pm
 /Win32API/
 /Win32CORE.pm
 /mro.pm
 /ops.pm
 /parent.pm
-/perlfaq*
+/perlfaq.pm
+/perlfaq.pod
+/perlfaq1.pod
+/perlfaq2.pod
+/perlfaq3.pod
+/perlfaq4.pod
+/perlfaq5.pod
+/perlfaq6.pod
+/perlfaq7.pod
+/perlfaq8.pod
+/perlfaq9.pod
 /perlglossary.pod
 /perlxs.pod
 /perlxstut.pod
 /version.pm
 /version.pod
 /version/
+
+# ex: set ro:
diff --git a/regen/lib_cleanup.pl b/regen/lib_cleanup.pl
new file mode 100644 (file)
index 0000000..ff756a7
--- /dev/null
@@ -0,0 +1,122 @@
+#!perl -w
+use strict;
+require 'regen/regen_lib.pl';
+use vars '$TAP';
+
+# For processing later
+my @ext;
+# Lookup hash of all directories in lib/ in a clean distribution
+my %libdirs;
+
+open my $fh, '<', 'MANIFEST'
+    or die "Can't open MANIFEST: $!";
+
+while (<$fh>) {
+    if (m<^((?:cpan|dist|ext)/[^/]+/              # In an extension directory
+           (?!t/|private/|corpus/|demo/|testdir/) # but not a test or similar
+           \S+                                    # filename characters
+           (?:\.pm|\.pod|_pm\.PL|_pod\.PL))       # useful ending
+           (?:\s|$)                               # whitespace or end of line
+          >x) {
+        push @ext, $1;
+    } elsif (m!^lib/([^ \t\n]+)/[^/ \t\n]+!) {
+        # All we are interested in are shipped directories in lib/
+        # leafnames (and package names) are actually irrelevant.
+        my $dirs = $1;
+        do {
+            # lib/Pod/t is in MANIFEST, but lib/Pod is not. Rather than
+            # special-casing this, generalise the code to ensure that all
+            # parent directories of anything add are also added:
+            ++$libdirs{$dirs}
+        } while ($dirs =~ s!/.*!!);
+    }
+}
+
+close $fh
+    or die "Can't close MANIFEST: $!";
+
+# Lines we need in lib/.gitignore
+my %ignore;
+
+FILE:
+foreach my $file (@ext) {
+    my ($extname, $path) = $file =~ m!^(?:cpan|dist|ext)/([^/]+)/(.*)!
+        or die "Can't parse '$file'";
+
+    if ($path =~ /\.pod$/) {
+        unless ($path =~ s!^lib/!!) {
+            # ExtUtils::MakeMaker will install it to a path based on the
+            # extension name:
+            if ($extname =~ s!-[^-]+$!!) {
+                $extname =~ tr!-!/!;
+                $path = "$extname/$path";
+            }
+        }
+    } elsif ($extname eq 'Unicode-Collate'  # Trust the package lines
+             || $extname eq 'Encode'        # Trust the package lines
+             || $path eq 'win32/Win32.pm'   # Trust the package line
+             || ($path !~ tr!/!!            # No path
+                 && $path ne 'DB_File.pm'   # ... but has multiple package lines
+                )) {
+        # Too many special cases to encode, so just open the file and figure it
+        # out:
+        my $package;
+        open my $fh, '<', $file
+            or die "Can't open $file: $!";
+        while (<$fh>) {
+            if (/^\s*package\s+([A-Za-z0-9_:]+)/) {
+                $package = $1;
+                last;
+            }
+        }
+        close $fh
+            or die "Can't close $file: $!";
+        die "Can't locate package statement in $file"
+            unless defined $package;
+        $package =~ s!::!/!g;
+        $path = "$package.pm";
+    } else {
+        if ($path =~ s/\.PL$//) {
+            # .PL files generate other files. By convention the output filename
+            # has the .PL stripped, and any preceding _ changed to ., to comply
+            # with historical VMS filename rules that only permit one .
+            $path =~ s!_([^_/]+)$!.$1!;
+        }
+        $path =~ s!^lib/!!;
+    }
+    my @parts = split '/', $path;
+    my $prefix = shift @parts;
+    while (@parts) {
+        if (!$libdirs{$prefix}) {
+            # It is a directory that we will create. Ignore everything in it:
+            ++$ignore{"/$prefix/"};
+            next FILE;
+        }
+        $prefix .= '/' . shift @parts;
+        # If we've just shifted the leafname back onto $prefix, then @parts is
+        # empty, so we should terminate this loop.
+    }
+    # We are creating a file in an existing directory. We must ignore the file
+    # explicitly:
+    ++$ignore{"/$path"};
+}
+
+if ($TAP && !-d '.git' && !-f 'lib/.gitignore') {
+    print "ok # skip not being run from a git checkout, hence no lib/.gitignore\n";
+    exit 0;
+}
+
+$fh = open_new('lib/.gitignore', '>',
+               { by => $0,
+                 from => 'MANIFEST and parsing files in cpan/ dist/ and ext/'});
+
+print $fh <<"EOT";
+# If this generated file has problems, it may be simpler to add more special
+# cases to the top level .gitignore than to code one-off logic into the
+# generation script $0
+
+EOT
+
+print $fh "$_\n" foreach sort keys %ignore;
+
+read_only_bottom_close_and_rename($fh);