# A Debhelper build system for cabalized Haskell packages.
#
# Copyright © 2015  Bogatov Dmitry <KAction@gnu.org>
# Copyright © 2021  Felix Lechner
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

=pod

=head1 NAME

Debian::Debhelper::Buildsystem::haskell -- Debhelper build system for cabal-based Haskell packages

=head1 DESCRIPTION

The dh-haskell package provides a build system for Debhelper which can be used
this way:

 %:
 	dh $@ --build-system=haskell

Usually it is all you need to know, and maybe you may want to adjust
DEB_BUILD_OPTIONS I<noopt> and I<nocheck>.  If you want to know precisely what
and how is performed, read on implementation section.

=head1 IMPLEMENTATION

=cut

package Debian::Debhelper::Buildsystem::haskell;

use v5.20;
use warnings;
use utf8;

use parent qw(Debian::Debhelper::Buildsystem);

use Const::Fast;
use Debian::Debhelper::Dh_Lib;
use IPC::Run3;
use List::SomeUtils qw(any);
use Path::Tiny;

const my $SPACE => q{ };
const my $DOT => q{.};

const my $CURRENT_DIRECTORY => $DOT;

const my $WAIT_STATUS_SHIFT => 8;

sub DESCRIPTION {
    return 'cabalized Haskell packages';
}

sub check_auto_buildable {
    my ($self, $step) = @_;

    my $sourcedir = $self->get_sourcedir;

    return 1
      if <$sourcedir/*.cabal>;

    return 0;
}

sub new {
    my ($class, @remaining) = @_;

    my $self = $class->SUPER::new(@remaining);

    $self->enforce_in_source_building;

    # set a dummy HOME variable; Cabal expects one
    $ENV{HOME} = '/homedoesnotexistatbuildtime';

    $ENV{DEB_DEFAULT_COMPILER} //= 'ghc';

    my @cabal_candidates= <*.cabal>;

    error('No cabal file found')
      unless @cabal_candidates;

    error('More than one cabal file')
      if @cabal_candidates > 1;

    my $cabal_path = $cabal_candidates[0];
    my $cabal_contents = path($cabal_path)->slurp_utf8;

    error('Cannot get package name from cabal file')
      unless $cabal_contents =~ /^ name \s* : \s* (\S*) \s* $/imx;

    my $package_name = lc $1;

    $ENV{CABAL_PACKAGE} //= $package_name;

    error('Cannot get package version from cabal file')
      unless $cabal_contents =~ /^ version \s* : \s* (\S*) \s* $/imx;

    my $package_version = $1;

    $ENV{CABAL_VERSION} = $package_version;

    $ENV{DEB_ENABLE_TESTS} //= 'no';
    $ENV{DEB_ENABLE_HOOGLE} //= 'yes';

    $ENV{"DEB_DH_GENCONTROL_ARGS_libghc-$ENV{CABAL_PACKAGE}-dev"}
      .= '-- -DGHC-Package=\${haskell:ghc-package}';

    $ENV{ENABLE_PROFILING}= '--enable-library-profiling'
      if any { /^libghc-$ENV{CABAL_PACKAGE}-prof$/ } @{$dh{DOPACKAGES}};

    $ENV{GHC_HAS_INTERPRETER} = 'yes'
      if qx{ghc --info} =~ m{Have interpreter.*YES};
    $ENV{GHC_HAS_SMP} = 'yes'
      if qx{ghc --info} =~ m{Support SMP.*YES};

    $ENV{NO_GHCI_FLAG} = '--ghc-option=-DDEBIAN_NO_GHCI'
      unless -e '/usr/bin/ghci';

    $ENV{DEB_COMPRESS_EXCLUDE} .= $SPACE . '.haddock .hs .txt';

    # (because we do not (yet) have shlibs files for libHS libraries)
    $ENV{DEB_DH_SHLIBDEPS_ARGS_ALL} .= $SPACE . '-- --ignore-missing-info';
    $ENV{DEB_DH_MAKESHLIBS_ARGS_ALL} .= $SPACE . '-XlibHS';

    # Starting with debhelper 9.20151219, dh_strip generates automatic
    # debug packages. GHC does not produce debugging symbols so the dbgsym
    # packages are empty. Disables them.
    $ENV{DEB_DH_STRIP_ARGS} .= $SPACE . '--no-automatic-dbgsym';

    $ENV{DEB_SETUP_BIN_NAME} //= 'debian/hlibrary.setup';

    # you probably do not need to touch these
    $ENV{GHC6_VERSION} = qx{ghc --numeric-version};
    $ENV{GHC_VERSION} = qx{ghc --numeric-version};

    $ENV{DEB_HADDOCK_OPTS}
      .= '--html --hoogle --haddock-options="--mathjax=file:///usr/share/javascript/mathjax/MathJax.js"';
    $ENV{DEB_HADDOCK_OPTS} .= '--hyperlink-source'
      unless exists $ENV{DEB_NO_IMPLICIT_HADDOCK_HYPERLINK};

    $ENV{MAKEFILE} = 'debian/hlibrary.Makefile';

    $ENV{OPTIMIZATION} = '--disable-optimization'
      if $ENV{DEB_BUILD_OPTIONS} =~ /noopt/;

    $ENV{TESTS} = '--enable-tests'
      if $ENV{DEB_ENABLE_TESTS} eq 'yes'
      && $ENV{DEB_BUILD_OPTIONS} !~ /nocheck/;

    $ENV{DEB_BUILD_DEPENDENCIES} = 'build-arch';

    $ENV{DEB_LINTIAN_OVERRIDES_FILE}
      = "debian/libghc-$ENV{CABAL_PACKAGE}-dev.lintian-overrides";

    return $self;
}

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

    $self->library_function('make_setup_recipe');
    $self->library_function('configure_recipe');

    return;

}

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

    $self->library_function('build_recipe');

    return;
}

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

    my @command = (
        $ENV{DEB_SETUP_BIN_NAME},
        'copy', '--builddir=dist-ghc', '--destdir=debian/tmp'
    );
    run3(\@command);

    my $exitcode = $?;
    my $status = ($exitcode >> $WAIT_STATUS_SHIFT);

    return;
}

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

    $self->library_function('clean_recipe');

    return;
}

sub library_function {
    my ($self, $recipe) = @_;

    my $LIBRARY = '/usr/share/haskell-devscripts/Dh_Haskell.sh';

    my @command = ('bash', '-c', "source $LIBRARY && $recipe");
    run3(\@command);

    my $exitcode = $?;
    my $status = ($exitcode >> $WAIT_STATUS_SHIFT);

    return $status;
}

1;

# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et
