The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package CPAN::MakeMaker;
$VERSION = '0.10';
@EXPORT = qw(WriteMakefile prompt);
use strict;
use ExtUtils::MakeMaker();
use File::Spec;
use Cwd;
use base 'Exporter';
*prompt = \&ExtUtils::MakeMaker::prompt;
sub PRINT;
if (not defined &PRINT) {
    *PRINT = sub { my @args = @_; chomp $args[-1]; print @args, "\n"; };
}

sub WriteMakefile {
    my %args = @_;
    $args{NAME} = determine_NAME()
      unless defined $args{NAME};
    $args{VERSION} = determine_VERSION()
      unless defined $args{VERSION} or defined $args{VERSION_FROM};
    update_manifest();

    ExtUtils::MakeMaker::WriteMakefile(%args);
    append_to_makefile();
}

sub determine_NAME {
    my $NAME = '';
    my @modules = glob('*.pm'), grep {/\.pm$/} find_files('lib');
    if (@modules == 1) {
        open MODULE, $modules[0] or die $!;
        while (<MODULE>) {
            next if /^\s*#/;
            if (/^\s*package\s+(\w[\w:]*)\s*;\s*$/) {
                $NAME = $1;
            }
            last;
        }
    }
    die <<END unless length($NAME);
Can't determine a NAME for this distribution.
Please pass a NAME parameter to the WriteMakefile function in Makefile.PL.
END
    return $NAME;
}

sub find_files {
    my ($file, $path) = @_;
    $path = '' if not defined $path;
    $file = "$path/$file" if length($path);
    if (-f $file) {
        return ($file);
    }
    elsif (-d $file) {
        my @files = ();
        local *DIR;
        opendir(DIR, $file) or die "Can't opendir $file";
        while (my $new_file = readdir(DIR)) {
            next if $new_file =~ /^(\.|\.\.)$/;
            push @files, find_files($new_file, $file);
        }
        return @files;
    }
    return ();
}
    
sub determine_VERSION {
    my $VERSION = '';
    my @modules = glob('*.pm'), grep {/\.pm$/} find_files('lib');
    if (@modules == 1) {
        eval {
            $VERSION = ExtUtils::MM_Unix->parse_version($modules[0]);
        };
        print STDERR $@ if $@;
    }
    die <<END unless length($VERSION);
Can't determine a VERSION for this distribution.
Please pass a VERSION parameter to the WriteMakefile function in Makefile.PL.
END
    return $VERSION;
}

sub update_manifest {
    my ($manifest, $manifest_path, $relative_path) = read_manifest();
    my $manifest_changed = 0;

    my %manifest;
    for (@$manifest) {
        my $path = $_;
        chomp $path;
        $path =~ s/^\.[\\\/]//;
        $path =~ s/[\\\/]/\//g;
        $manifest{$path} = 1;
    }

    for (find_files('CPAN')) {
        my $filepath = $_;
        $filepath = "$relative_path/$filepath"
          if length($relative_path);
        unless (defined $manifest{$filepath}) {
            PRINT 'Updating your MANIFEST file:'
              unless $manifest_changed++;
            PRINT "  Adding '$filepath'";
            push @$manifest, "$filepath\n";
            $manifest{$filepath} = 1;
        }
    }

    if ($manifest_changed) {
        open MANIFEST, "> $manifest_path" 
          or die "Can't open '$manifest_path' for output:\n$!";
        print MANIFEST for @$manifest;
        close MANIFEST;
    }
}

sub read_manifest {
    my $manifest = [];
    my $manifest_path = '';
    my $relative_path = '';
    my @relative_dirs = ();
    my $cwd = cwd();
    my @cwd_dirs = File::Spec->splitdir($cwd);
    while (@cwd_dirs) {
        last unless -f File::Spec->catfile(@cwd_dirs, 'Makefile.PL');
        my $path = File::Spec->catfile(@cwd_dirs, 'MANIFEST');
        if (-f $path) {
            $manifest_path = $path;
            last;
        }
        unshift @relative_dirs, pop(@cwd_dirs);
    }
    unless (length($manifest_path)) {
        die "Can't locate the MANIFEST file for '$cwd'\n";
    }
    $relative_path = join '/', @relative_dirs
      if @relative_dirs;

    open MANIFEST, $manifest_path 
      or die "Can't open $manifest_path for input:\n$!";
    @$manifest = <MANIFEST>;
    close MANIFEST;

    return ($manifest, $manifest_path, $relative_path);
}

sub append_to_makefile {
    open MAKEFILE, '>> Makefile'
      or die "CPAN::MakeMaker::WriteMakefile can't append to Makefile:\n$!";

    print MAKEFILE <<MAKEFILE;
# Well, not quite. CPAN::MakeMaker is adding this:

.PHONY = cpurge chelp

# The cpurge target can be used by the author of this module to remove
# files added by CPAN::MakeMaker. The files will not be removed from
# the MANIFEST. You'll need to do that yourself.
cpurge :: purge
	\$(RM_RF) CPAN

# Authors can use this target as a shortcut for 'perldoc CPAN::MakeMaker'
chelp ::
	perldoc CPAN::MakeMaker

# The End is here ==>
MAKEFILE

    close MAKEFILE;
}

1;