package Debian::Debhelper::Buildsystem::leiningen;

=head1 NAME

leiningen -- debhelper build system class for Clojure packages

=head1 DESCRIPTION

See L<dh-clojure-lein(7)> for additional information.

=head1 SEE ALSO

L<dh-clojure-lein(7)>, L<dh(1)>, and L<lein(1)>

=cut

use Cwd;
use File::Path qw(remove_tree);
use strict;
use warnings;
use parent qw(Debian::Debhelper::Buildsystem);
use Debian::Debhelper::Dh_Lib;

sub DESCRIPTION {
    'Leiningen'
}

sub DEFAULT_BUILD_DIRECTORY {
    'target'
}

sub check_auto_buildable {
    my $this = shift;
    return $this->get_sourcepath('project.clj') ? 0 : 1;
}

my $lein = '/usr/bin/lein';
my $reltmp = 'debian/dh-clojure/tmp';
my $abstmp = getcwd . '/debian/dh-clojure/tmp';
my $local_repo = "$abstmp/maven-repo";

sub new {
    my $class = shift;
    my $this  = $class->SUPER::new(@_);

    # key project attributes
    $this->{name} = $this->_get_project('name');
    $this->{version} = $this->_get_project('version');

    # path to jar artifacts
    $this->{artifact} = "target/$this->{name}-$this->{version}.jar";
    $this->{test_artifact} = "target/test/$this->{name}-$this->{version}-test.jar";

    # Absolute because (at least) subprocs might change the parent
    # directory and run lein, e.g. DH_CLOJURE_LEIN_CREATE_MAVEN_REPO.
    $ENV{'LEIN_HOME'} = "$abstmp/lein-home";

    # lein may not attempt to access the network
    # (Debian policy, section 4.9)
    $ENV{'LEIN_OFFLINE'} = 'true';

    return $this;
}

sub _get_project {
    my $this = shift;
    my ($property) = @_;

    my $cmd = "DH_CLOJURE_LEIN_BUILD=true $lein"
        . " update-in : assoc :local-repo '\"$local_repo\"' --"
        . " update-in :$property println --"
        . ' version';

    my $output = `$cmd`;
    if ($?) {
        print STDERR "$output\n"; # because a stacktrace shows up there
        error_exitcode($cmd)
    }

    my ($value) = split(/\n/, $output);
    return $value;
}

sub _do_lein {
    my $this = shift;
    doit({'update_env' => {'DH_CLOJURE_LEIN_BUILD' => 'true'}},
         $lein, 'update-in', ':', 'assoc', ':local-repo', "\"$local_repo\"",
         '--', @_);
}

sub _create_maven_repo {
    # This function also runs at the start of clean() to provide the
    # normal environment for lein clean (including dh-clojure-lein),
    # so it should be careful to "always" work.
    doit('mkdir', '-p', $abstmp);
    # This is currently for dh-clojure internal use only.
    my $override = $ENV{'DH_CLOJURE_LEIN_CREATE_MAVEN_REPO'};
    if ($override) {
        doit($override, '/usr/share/maven-repo', "$abstmp/maven-repo");
    } else {
        remove_tree("$abstmp/maven-repo");
        doit('ln', '-sf', '/usr/share/maven-repo', "$abstmp/maven-repo");
    }
}

sub configure {
    _create_maven_repo();
}

sub build {
    my $this = shift;

    # generate the pom artifact
    $this->_do_lein('pom', "$reltmp/pom.xml"); # only accepts relative paths

    # clean the pom (without applying any version transformations) to
    # remove unwanted elements that may originate from lein and/or
    # project.clj
    doit('mh_cleanpom', '--no-rules', '--has-package-version',
         "-p$dh{MAINPACKAGE}", "$reltmp/pom.xml", "$reltmp/pom.xml");

    # generate the jar artifact
    $this->_do_lein('jar');

    doit('test', '-f', $this->{artifact});
}

sub install {
    my $this = shift;
    my $pomsfile = $dh{MAINPACKAGE} . '.poms';
    my $usj_name = defined($ENV{DH_CLOJURE_USJ_NAME})
        ? $ENV{DH_CLOJURE_USJ_NAME} : $this->{name};

    # write debian/<package>.poms file for maven-repo-helper
    my $pomsline = "$reltmp/pom.xml --artifact=$this->{artifact} --usj-name=$usj_name --java-lib";
    complex_doit("echo '$pomsline' > debian/$pomsfile");

    # add test artifact to poms file
    if (defined($ENV{DH_CLOJURE_INSTALL_TEST_JAR})
        && $ENV{DH_CLOJURE_INSTALL_TEST_JAR} eq 'true') {
        $pomsline = "$reltmp/pom.xml --artifact=$this->{test_artifact}"
            . " --usj-name=$usj_name-test --java-lib --classifier=test";
        complex_doit("echo '$pomsline' >> debian/$pomsfile");
    }

    # install build artifacts to /usr/share/{java,maven-repo}
    doit('mh_install');

    # Since we handle our own .pom files, we don't want
    # mh_resolve_dependencies to touch them, and right now it will
    # (via mh_patchpoms) unless .debianVersion exists.  It's easy to
    # see where that happens in the current source, but it's not
    # documented as far as I've seen, and so we may eventually want to
    # consider pursuing a --no-patch option or something.
    doit('touch', '.debianVersion');

    # generate ${maven:Depends} substvar
    doit('mh_resolve_dependencies', '--non-interactive', '--offline', '--build', "-p$dh{MAINPACKAGE}", '--non-explore');
}

sub test {
    my $this = shift;
    $this->_do_lein('test');
}

sub clean {
    my $this = shift;
    my $pomsfile = $dh{MAINPACKAGE} . '.poms';

    _create_maven_repo(); # provide dh-clojure-lein
    $this->_do_lein('clean');
    doit('rm', '-f', 'debian/' . $pomsfile, '.debianVersion', '.lein-failures');
    remove_tree($abstmp);
    doit('rmdir', '--ignore-fail-on-non-empty', 'debian/dh-clojure');
}

1;
