package DhMakeELPA::MELPA;

use strict;
use warnings;

=head1 NAME

DhMakeELPA::MELPA - functions to interact with MELPA

=cut

use Array::Utils qw{array_minus};
use LWP::Simple qw{get};

use Exporter qw(import);
our @EXPORT = qw(package_files_list);

=head1 METHODS

=over

=item package_files_list(I<package>)

Query MELPA to return the list of files that the recipe for the latest
version of the given package claims to belong to the package.  If the
recipe does not specify a list of files (i.e. all files in upstream's
repository are part of one ELPA package), this function will return an
array containing the item "*.el".

Note that this can give the wrong result if upstream has re-organised
their repo since the release being packaged.

=cut

# TODO what if the .el files are in subdirectories?  Look at magit's
# *.elpa files for an example of this

# TODO option to turn this query off during a refresh to avoid the
# caveat given above

sub package_files_list {
    my ($package) = @_;
    my $recipe = get("https://raw.githubusercontent.com/melpa/melpa/master/recipes/" . $package)
        or die "W: Could not download recipe for $package from MELPA";

    # insert MELPA's default globs if necessary (edited slightly)
    my $defaults = <<EOT;
"*.el"
 (:exclude ".dir-locals.el" "test.el" "tests.el" "*-test.el" "*-tests.el")
EOT
    $recipe =~ s/:defaults/$defaults/;

    # now see if there is a files array at all
    if ($recipe =~ m/:files\s\((.*)\)/s)
    {
        # parse out the lisp list into perl arrays
        my $lisp_files_list = $1;
        $lisp_files_list =~ s/\s+/ /g;
        my $includes, my $excludes;
        # is there an :exclude list?
        if ($lisp_files_list =~ m/(.*)\(:exclude\s(.*)\)(.*)/) {
            $includes = $1 . $3;
            $excludes = $2;
        }
        # no exclude list: include all
        else {
            $includes = $lisp_files_list;
            $excludes = "";
        }
        # trim and split them up
        $includes =~ s/^\s*\"(.*)\"[\s)]*$/$1/;
        $excludes =~ s/^\s*\"(.*)\"[\s)]*$/$1/;
        my @includes = split /\" \"/, $includes;
        my @excludes = split /\" \"/, $excludes;

        # perform the globs
        @includes = map { glob($_) } @includes;
        @excludes = map { glob($_) } @excludes;

        # sometimes MELPA includes non-el files in its :files
        @includes = grep { $_ =~ /\.el$/ } @includes;

        return array_minus( @includes, @excludes );
    }
    # no files array: we can assume that all the *.el files belong to this package
    else {
        return ("*.el");
    }
}
