The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package File::ShareDir::Tarball;
BEGIN {
  $File::ShareDir::Tarball::AUTHORITY = 'cpan:YANICK';
}
{
  $File::ShareDir::Tarball::VERSION = '0.2.1';
}
# ABSTRACT: Deal transparently with shared files distributed as tarballs


use strict;
use warnings;

use parent qw/ Exporter /;

use Carp;

use File::ShareDir;
use Archive::Tar;
use File::Temp qw/ tempdir /;
use File::chdir;

our @EXPORT_OK   = qw{
    dist_dir dist_file
};
our %EXPORT_TAGS = (
    all => [ @EXPORT_OK ],
);

my $shared_files_tarball = 'shared-files.tar.gz';

# we don't want to extract the same dirs again and 
# again within a single program
my %DIR_CACHE;

sub dist_dir {
    my $dist = shift;

    return $DIR_CACHE{$dist} if $DIR_CACHE{$dist};

    my $dir = File::ShareDir::dist_dir($dist);

    # no tarball? Assume regular shared dir
    return $DIR_CACHE{$dist} = $dir 
        unless -f "$dir/$shared_files_tarball";

    my $archive = Archive::Tar->new;
    $archive->read("$dir/$shared_files_tarball");

    # because that would be a veeery bad idea
    croak "archive '$shared_files_tarball' contains files with absolute path, aborting"
        if grep { m#^/# } $archive->list_files;

    my $tmpdir = tempdir( CLEANUP => 1 );
    local $CWD = $tmpdir;

    $archive->extract;

    return $DIR_CACHE{$dist} = $tmpdir;
}

sub dist_file {
    my $dist = File::ShareDir::_DIST(shift);
    my $file = File::ShareDir::_FILE(shift);

    my $path = dist_dir($dist).'/'.$file;

	return undef unless -e $path;

    croak("Found dist_file '$path', but not a file") 
        unless -f $path;

    croak("File '$path', no read permissions") 
        unless -r $path;

	return $path;
}


1;

__END__

=pod

=head1 NAME

File::ShareDir::Tarball - Deal transparently with shared files distributed as tarballs

=head1 VERSION

version 0.2.1

=head1 SYNOPSIS

    use File::ShareDir::Tarball ':all';

    # use exactly like File::ShareDir
    $dir = dist_dir('File-ShareDir');

=head1 DESCRIPTION

If the shared files of a distribution are contained in a
tarball (see L<Dist::Zilla::Plugin::ShareDir::Tarball> for
why you would want to do that), automatically 
extract the archive in a temporary
directory and return the path to that directory. If called for a regular distribution without a bundle file
(C<shared-files.tar.gz>), it'll return the original shared dir. 
In other words,
from the consumer point of view, it'll behave just like L<File::ShareDir>.

=head1 EXPORT TAGS

=head2 :all

Exports C<dist_dir()> and C<dist_file()>.

=head1 EXPORTABLE FUNCTIONS

=head2 dist_dir( $distribution )

Behaves just like C<dist_dir()> from L<File::ShareDir>.

=head2 dist_file( $distribution, $file )

Behaves just like C<dist_file()> from L<File::ShareDir>.

=head1 SEE ALSO

=over

=item L<Test::File::ShareDir>

To test or use a shared dir that is not deployed yet. 

=item L<Dist::Zilla::Plugin::ShareDir::Tarball>

L<Dist::Zilla> plugin to create the tarball effortlessly.

=item L<Module::Build::CleanInstall>

Provides an alternative to this module by subclassing L<Module::Build> and,
upon installation, remove the files from previous installations as given in
the I<packlist>.

=back

=head1 AUTHOR

Yanick Champoux <yanick@babyl.dyndns.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Yanick Champoux.

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