#!/usr/bin/perl

# Copyright © 2022 Felix Lechner <felix.lechner@lease-up.com>
#
# based on a shell script by the same name
#     by Arjan Oosting <arjan@debian.org>
#     and Joachim Breitner <nomeata@debian.org>
#
# 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/>.

use v5.20;
use warnings;
use utf8;

use Const::Fast;
use File::Basename;
use Getopt::Long ();
use List::SomeUtils qw(none);
use Path::Tiny;
use Unicode::UTF8 qw(encode_utf8);

use Debian::Debhelper::Buildsystem::Haskell::Recipes qw(
  run
  installable_type
  installable_hc
  find_config_for_ghc
  ghc_pkg_command
  load_ghc_database
  hashed_id_to_virtual_installable
);

const my $SPACE => q{ };
const my $COMMA => q{,};
const my $NEWLINE => qq{\n};

my $program_name = basename($0);

# for a call from ghc's d/rules
$ENV{DEB_DEFAULT_COMPILER} ||= 'ghc';
$ENV{DEB_GHC_DATABASE} ||= 'debian/tmp-db';

my @excludes;

my %options = (
    'exclude|X=s' => \@excludes,
    'help|h' => \&show_help,
);

Getopt::Long::Configure('gnu_getopt', 'pass_through');
Getopt::Long::GetOptions(%options)
  or die encode_utf8("error parsing options\n");

my @args_bytes = grep { /^-/ } @ARGV;
my @configs = grep { !/^-/ } @ARGV;

die encode_utf8("Installed package description file $_ can not be found")
  for grep { !-e } @configs;

$ENV{DH_EXCLUDES} = join($SPACE, @excludes);

my $output = run('dh_listpackages', @args_bytes);
chomp $output;

my @installables = split($SPACE, $output);
for my $installable (@installables) {

    my $type = installable_type($installable);

    @configs = find_config_for_ghc($installable)
      unless @configs;

    warn encode_utf8(
        "$program_name: No installed package description files found")
      unless @configs;

    my $compiler = installable_hc($installable) || $ENV{DEB_DEFAULT_COMPILER};

    my $ghc_pkg = ghc_pkg_command();
    load_ghc_database($ghc_pkg, $ENV{DEB_GHC_DATABASE}, @configs);

    my @hashed_ids;
    for my $config (@configs) {

        my $name = path($config)->basename(qr{ [.]conf $}x);
        push(
            @hashed_ids,
            run(
                $ghc_pkg, '--package-db', $ENV{DEB_GHC_DATABASE},
                qw{--simple-output field},
                $name, 'id'
            ));
    }

    my @provides;
    push(
        @provides,
        hashed_id_to_virtual_installable(
            $compiler, $_, $type,
            $ghc_pkg, '--package-db', $ENV{DEB_GHC_DATABASE}))for @hashed_ids;

    my $substvars_path = "debian/$installable.substvars";
    replace_line($substvars_path, 'haskell:Provides',
        join($COMMA . $SPACE, @provides));

    if ($type eq 'dev') {

        replace_line($substvars_path, "haskell:$compiler-package",
            join($SPACE, @hashed_ids));
    }
}

exit;

sub replace_line {
    my ($path, $field, $value) = @_;

    path($path)->touch;

    my @lines = grep { !m{^ $field = }x } path($path)->lines_utf8;

    push(@lines, "$field=$value" . $NEWLINE);

    path($path)->spew_utf8(@lines);

    return;
}

sub show_help {
    my $message =<<"EOT";
Usage: $program_name [options] cabal-file ...

Options:
    -X, --exclude INSTALLABLE    exclude INSTALLABLE from processing
EOT

    print encode_utf8($message);

    exit;
}

=head1 NAME

dh_haskell_provides - calculates Haskell virtual package names on Cabalized libraries

=head1 SYNOPSIS

B<dh_haskell_provides> [S<I<debhelper options>>]
[B<-X>I<package>]
[B<--exclude=>I<package>]
[S<I<file>> ...]

=head1 DESCRIPTION

dh_haskell_provides is a debhelper program that calculates the correct virtual
package to provide, so that dependencies can guarantee ABI stability.

For a package with an idea of package-version-longhashstring, it generates a
virtual package of the form libghc-package-dev-version-longh for the -dev
package and libghc-package-prof-version-longh for the prof package
respectively.

This script writes the debian/$package.substvars file, including in it the
haskell:Provides.  So, to use this package, include in the Provides: field in
debian/control ${haskell:Provides}.

=head1 SEE ALSO

L<dh_haskell_depends(1)>
L<dh_haskell_shlibdeps(1)>
L<debhelper(7)>

=head1 AUTHOR

Joachim Breitner <nomeata@debian.org>

Based on ideas in dh_ocaml.

=cut

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