package Dist::Zilla::Plugin::GatherFromManifest;

# $Id: GatherFromManifest.pm 23 2010-09-25 12:01:20Z stro $

use strict;
use warnings;

BEGIN {
  $Dist::Zilla::Plugin::GatherFromManifest::VERSION = '1.001';
}

=head1 NAME

Dist::Zilla::Plugin::GatherFromManifest - gather all files from MANIFEST

=head1 VERSION

version 1.001

=head1 SYNOPSIS

    [GatherFromManifest]

=head1 DESCRIPTION

This is a L<FileGatherer|Dist::Zilla::Role::FileGatherer>plugin, which
allows you to implicitly specify which files should be built into
distibution.

This module offers a different approach to default
L<Dist::Zilla::Plugin::GatherDir> which adds ALL files to distribution and
L<Dist::Zilla::Plugin::ManifestSkip> which prunes files listed in
MANIFEST.SKIP.

You should replace [GatherDir] with [GatherFromManifest] and make sure you
have a MANIFEST file. It's quite useful if you're converting existing
package to Dist::Zilla.

If you plan to use [License], [Readme] or any other module producing
autogenerated files, you should remove corresponding file names from
MANIFEST to avoid duplication errors.

=head1 ATTRIBUTES

=head2 root

This is the directory in which to look for files.  If not given, it defaults to
the dist root -- generally, the place where your F<dist.ini> or other
configuration file is located.

=head2 prefix

This parameter can be set to gather all the files found under a common
directory.  See the L<description block in GatherDir documentation|Dist::Zilla::Plugin::GatherDir#DESCRIPTION> for an example.

=head1 SUBROUTINES/METHODS

=cut

# ABSTRACT: build files that appear in a MANIFEST file

use Moose;
use Moose::Autobox;
use MooseX::Types::Path::Class qw(Dir File);
with 'Dist::Zilla::Role::FileGatherer';

use ExtUtils::Manifest;

use File::Find::Rule;
use File::HomeDir;
use File::Spec;
use Path::Class;

use namespace::autoclean;

has root => (
    is   => 'ro',
    isa  => Dir,
    lazy => 1,
    coerce   => 1,
    required => 1,
    default  => sub { shift->zilla->root },
);

has prefix => (
    is  => 'ro',
    isa => 'Str',
    default => '',
);

has manifest => (is => 'ro', required => 1, default => 'MANIFEST');

=head2 gather_files

Overridden method implementing gathering functionality.

=cut

sub gather_files {
    my ($self) = @_;

    my $manifest = $self->zilla->root->file( $self->manifest );
    unless (-f $manifest) {
        $self->log_fatal("Cannot read manifest file: ", $manifest);
    }

    my $root = "" . $self->root;
    $root =~ s{^~([\\/])}{File::HomeDir->my_home . $1}ex;
    $root = Path::Class::dir($root);

    $manifest = File::Spec->catdir($root, $manifest);

    my $list = ExtUtils::Manifest::maniread($manifest);

    my @files;
    FILE: for my $filename (keys %$list) {
        push @files, $self->_file_from_filename($filename);
    }

    for my $file (@files) {
        (my $newname = $file->name) =~ s{\A\Q$root\E[\\/]}{}gx;
        $newname = File::Spec->catdir($self->prefix, $newname) if $self->prefix;
        $newname = Path::Class::dir($newname)->as_foreign('Unix')->stringify;

        $file->name($newname);
        $self->add_file($file);
    }

    return;
}

sub _file_from_filename {
    my ($self, $filename) = @_;

    unless (-f $filename) {
        $self->log_fatal("Cannot read file from manifest: ", $filename);
    }

    return Dist::Zilla::File::OnDisk->new({
        name => $filename,
        mode => (stat $filename)[2] & oct(755), # kill world-writeability
    });
}

__PACKAGE__->meta->make_immutable;
no Moose;
1;

=head1 AUTHOR

Serguei Trouchelle <stro@cpan.org>

Some parts of code is borrowed from L<Dist::Zilla::Plugin::GatherDir> and L<Dist::Zilla::Plugin::ManifestSkip> written by Ricardo SIGNES <rjbs@cpan.org>

=head1 LICENSE AND COPYRIGHT

Copyright (c) 2010 by Serguei Trouchelle

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

