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(@_);

    # 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';
    $ENV{'DEB_TMP_LEIN_LOCAL_REPO'} = "$abstmp/maven-repo";

    _create_maven_repo();

    # key project attributes
    ($this->{group}, $this->{name}, $this->{version}) = $this->_get_project_info();

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

    return $this;
}

sub _get_project_info {
    my $this = shift;

    my $cmd = "DH_CLOJURE_LEIN_BUILD=true $lein"
        . " update-in :group println --"
        . " update-in :name println --"
        . " update-in :version println --"
        . ' version';

    my @output = `$cmd`;
    if ($?) {
        print STDERR "@output\n"; # because a stacktrace shows up there
        error_exitcode($cmd)
    }
    if ($#output != 6) {
        print STDERR "@output\n";
        error('ERROR: expected 7 output lines above')
    }
    chomp @output;
    return @output[0,2,4];
}

sub _do_lein {
    my $this = shift;
    doit({'update_env' => {'DH_CLOJURE_LEIN_BUILD' => 'true'}}, $lein, @_);
}

sub _create_maven_repo {
    # This function also runs at initialization to provide the
    # normal environment for lein commands (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 build {
    my $this = shift;

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

    # 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};
    my $maven_group_path = $this->{group} =~ tr/./\//r;
    my $maven_path = "debian/$dh{MAINPACKAGE}/usr/share/maven-repo/$maven_group_path/$this->{name}";

    # Install build artifacts to /usr/share/{java,maven-repo}.
    # This replaces the call to mh_install because we're unable to
    # pass the --no-rules switch to it, so that it avoids messing
    # with dependency versions in the pom file. The sequence below
    # must be followed exactly because mh_installjar consumes the
    # pom.properties file generated by mh_installpom.
	# -> upstream versioned
    doit('mh_installpom', "-p$dh{MAINPACKAGE}", '--no-rules', '--keep-pom-version', "$reltmp/pom.xml");
    doit('mh_installjar', "-p$dh{MAINPACKAGE}", '--skip-clean-pom', '--java-lib', "--usj-name=$usj_name", "$reltmp/pom.xml", $this->{artifact});
    if (defined($ENV{DH_CLOJURE_INSTALL_TEST_JAR})
        && $ENV{DH_CLOJURE_INSTALL_TEST_JAR} eq 'true') {
        doit('mh_installjar', "-p$dh{MAINPACKAGE}", '--skip-clean-pom', '--java-lib', '--classifier=test', "--usj-name=$usj_name-test", "$reltmp/pom.xml", $this->{test_artifact});
	}
	# -> debian versioned
    # here we don't call mh_installjar because we don't want a
    # second copy of the artifact under /usr/share/java so instead
    # just copy the symlink used for the upstream-version artifact
    doit('mh_installpom', "-p$dh{MAINPACKAGE}", '--no-rules', '--set-version=debian', "$reltmp/pom.xml");
    doit('cp', '-P', "$maven_path/$this->{version}/$this->{name}-$this->{version}.jar", "$maven_path/debian/$this->{name}-debian.jar");
    if (defined($ENV{DH_CLOJURE_INSTALL_TEST_JAR})
        && $ENV{DH_CLOJURE_INSTALL_TEST_JAR} eq 'true') {
        doit('cp', '-P', "$maven_path/$this->{version}/$this->{name}-$this->{version}-test.jar", "$maven_path/debian/$this->{name}-debian-test.jar");
    }

    # Reset debian.* POM properties because they're not generated
    # properly due to the "uncoventional" sequence above.
    foreach ("$maven_path/debian/$this->{name}-debian.pom", "$maven_path/$this->{version}/$this->{name}-$this->{version}.pom") {
        doit('xmlstarlet', 'ed', '-L', '-N', 'x=http://maven.apache.org/POM/4.0.0',
            '-d', '/x:project/x:properties/*',
            '-s', '/x:project/x:properties', '-t', 'elem', '-n', 'debian.hasPackageVersion',
            '-s', '/x:project/x:properties', '-t', 'elem', '-n', 'debian.originalVersion', '-v', $this->{version},
            '-s', '/x:project/x:properties', '-t', 'elem', '-n', 'debian.package', '-v', $dh{MAINPACKAGE},
            $_);
    }

    # 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');

    # Write a debian/<package>.poms file for mh_resolve_dependencies,
    # as there doesn't seem to be any other way for it to discover
    # our POM files.
    my $pomsline = "$maven_path/debian/$this->{name}-debian.pom";
    complex_doit("echo '$pomsline' > debian/$pomsfile");

    # This generates our ${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';

    $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;
