#/usr/bin/perl

use strict;
use warnings;

use ExtUtils::Manifest qw{ maniread manicopy };
use File::Find qw{};
use File::Path;
use File::pushd;
use File::Spec;

# --------------------------------------------------------------------------------
#
#   manidirs
#
#       my $manidirs = manidirs( $manifest );
#
#   Returns directories implicitly used in manifest..
#
sub manidirs($) {
    my ( $manifest ) = @_;
    my $manidirs = { '.' => '' };
    foreach my $file ( keys( %$manifest ) ) {
        while ( $file =~ m{^(.*)/} ) {
            $manidirs->{ $1 } = '';
            $file = $1;
        };
    };
    return $manidirs;
}; # sub manidirs


# --------------------------------------------------------------------------------
#
#   cleardist
#
#       cleardist( $manifest );
#
#   Remove from the current directory everything not listed in the manifest.
#
sub cleardist($$) {
    my ( $manifest, $distdir ) = @_;
    my $manidirs = manidirs( $manifest );
    my $dir = pushd( $distdir );
    File::Find::find(
        {
            no_chdir => 1,
            wanted => sub {
                my $entry = $_;
                my $name  = ExtUtils::Manifest::clean_up_filename( $entry );
                if ( -f $entry ) {
                    if ( not exists( $manifest->{ $name } ) ) {
                        unlink( $entry ) or die "Cannot delete $entry: $!\n";
                    };
                } elsif ( -d $entry ) {
                    if ( not exists( $manidirs->{ $name } ) ) {
                        File::Path::remove_tree( $name );
                        $File::Find::prune = 1;
                    };
                } else {
                    die "Oops";
                };
            },
        },
        File::Spec->curdir()
    );
}; # sub distclean


#
#   Parse command line arguments.
#
@ARGV < 3 and die "Not enough arguments: 3 arguments expected\n";
@ARGV > 3 and die "Too many arguments: 3 arguments expected\n";
my ( $srcdir, $distdir, $how ) = @ARGV;

#
#   Read the manifest.
#
my $manifest = maniread( File::Spec->catfile( $srcdir, $ExtUtils::Manifest::MANIFEST ) );

#
#   Copy required files to distdir.
#

$ExtUtils::Manifest::Quiet = 1;
manicopy( $manifest, $distdir, $how );

#
#   Clean all the extra files.
#
#   `filecheck' does not work well for my purpose: it ignores directories and
#   files listed in `MANIFEST.SKIP', while I really want to delete everything
#   not explicitly listed in MANIFEST.
#
cleardist( $manifest, $distdir );

exit( 0 );
