#! /usr/bin/perl
# $Id: mkmanifest 2784 2006-10-05 00:38:24Z rra $
#
# Generate a filename-only manifest from a source tree.
#
# This script generates a filename-only manifest from a source tree, excluding
# certain files according to .cvsignore files and several built-in rules.  It
# is intended to be used to support make check-manifest from the top level of
# the source tree.

require 5.005;

use strict;
use vars qw(%CVSIGNORE @FILES @IGNORE %INCLUDE);

use File::Find qw(find);

# The following regex patterns match files to be ignored wherever they are
# in the tree.  This is intended to handle files that CVS ignores by default
# or files that are present in the tree and in CVS but which are not included
# in releases.
@IGNORE = (qr%(\A|/)\.cvsignore\Z%, qr/\.[ao]\Z/, qr%(\A|/)CVS(/|\Z)%,
           qr%(\A|/)\.svn(/|\Z)%, qr%(\A|/)\.?\#%, qr/\.(old|bak|orig|rej)$/,
           qr%(\A|/)core\Z%, qr/~\Z/, qr%\Adebian(/|\Z)%,
           qr%\Apatches(/|\Z)%);

# A list of generated files that should be included in the manifest and
# therefore included in releases, but which are listed in .cvsignore.
%INCLUDE = map { $_ => 1 } qw(configure config.h.in src/utils/wa_keyring.1);

# Build a list of all the files ignored by rules in .cvsignore files.  Meant
# to be run as the wanted sub of a call to File::Find.  Stuff in .cvsignore
# that contains wildcards needs to be lifted into the list of @IGNORE regexes.
sub find_cvsignore {
    return unless $_ eq '.cvsignore';
    return unless -f;
    my $file = $_;
    $file =~ s%^\./%%;
    my @ignored;
    my $dir = $File::Find::dir;
    $dir =~ s%^\./?%%;
    if ($dir) {
        $dir .= '/';
    }
    open (CVSIGNORE, $_) or die "Cannot open $File::Find::name: $!\n";
    @ignored = map { $dir . $_ } map { split (' ', $_) } <CVSIGNORE>;
    close CVSIGNORE;
    for (@ignored) {
        if (/\*/) {
            my $pattern = $_;
            $pattern =~ s/\./\\./g;
            $pattern =~ s/\*/.*/g;
            push (@IGNORE, qr/\A$pattern\Z/);
        } else {
            $CVSIGNORE{$_}++;
        }
    }
}

# Build a list of all files in the tree that aren't ignored by .cvsignore
# files or listed in ignore regexes.
sub find_files {
    return if $_ eq '.';
    my $name = $File::Find::name;
    $name =~ s%^./%%;
    if ($INCLUDE{$name}) {
        push (@FILES, $name);
        return;
    }
    if ($CVSIGNORE{$name}) {
        $File::Find::prune = 1;
        return;
    }
    for my $pattern (@IGNORE) {
        return if $name =~ /$pattern/;
    }
    push (@FILES, $name);
}

find (\&find_cvsignore, '.');
find (\&find_files, '.');
print join ("\n", (sort @FILES), '');
