#!/usr/bin/perl -w
# arch-tag: Debhelper script for Haskell
#
# Copyright (C) 2004 John Goerzen <jgoerzen@complete.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 2 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, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

=head1 NAME

dh_haskell - Builds Cabalized libraries, calculates Haskell dependencies, and adds postinst and prerm Haskell scripts

=cut

use strict;
use File::Find;
use Debian::Debhelper::Dh_Lib;

=head1 SYNOPSIS

B<dh_haskell> [S<I<debhelper options>>] 

=head1 DESCRIPTION

dh_haskell is a debhelper program that helps with building Haskell libraries.

It does several things.  It can generat postinst and prerm scripts when
necessary.  It automates building libraries for the different supported
Haskell systems in Debian.  It generates substvars for your control
file so that the library packages depend on the appropriate packages.
In short, it can drive the entire process.

=head1 REQUIREMENTS

dh_haskell assumes that your packages are adhering to the draft Haskell policy.

Your control file must build the binary library files using packages named
libI<type>-I<name>-dev, where I<type> is ghc5, ghc6, or nhc98; and
I<name> is the name of your package.  These packages should be Architecture:
any.

If you build a Hugs package, name it libhugs-I<name>.  However, dh_haskell
will also accept libhugs-I<name>-dev for consistency.  Most Hugs packages
should be Architecture: all.  If your package uses foreign methods,
maybe it should be Architecture: any (please let me know if you have
an answer to that).

dh_haskell figures out how to build your package based on the I<type>,
so you must adhere to this naming scheme.

dh_haskell assumes that the Haskell Cabal (see www.haskell.org/cabal) can
be used to build your package.  It obtains package name and version
information from the Cabal Setup.Description file.

=head1 HOW TO PACKAGE A HASKELL LIBRARY

Start from a basic debian/ directory.  Add entries to Build-Depends for
haskell-devscripts and the compilers for any binaries you will build.

In the clause in control for each binary package, make sure to add
${haskell:Depends} to the Depends: line.

In rules, in the install target, add dh_haskell.  Your build and configure
targets should be empty.

Remember that you should add -a to all debhelper calls for multi-binary
packages.  That goes for dh_haskell too.

Your clean target should contain:

C<-./setup clean>
C<--rm -rf setup Setup.hi Setup.ho Setup.o .*config* dist>

That's it.  dh_haskell does the rest.

=head1 EXAMPLE

See the Debian source package for hunit.

=cut

init();

sub is_handled_package {
    my $pkgname = shift;
    if ($pkgname =~ m/^lib(ghc5|ghc6|nhc98|hugs)-.+-dev$/) {
        return 1;
    } elsif ($pkgname =~ m/libhugs-.+$/) {
        return 1;
    } else {
        return 0;
    }
}

sub type_of_package {
    my $pkgname = shift;
    if ($pkgname =~ m/^libhugs-.+$/) {
        return "hugs";
    } else {
        my @pn = ($pkgname =~ m/^lib(ghc5|ghc6|nhc98|hugs)-.+-dev$/);
        return $pn[0];
    }
}

sub version_of_debpkg {
    my $pkgname = shift;
    my $retval = `dpkg -s $pkgname | grep ^Version | awk '{print \$2}'`;
    chomp $retval;
    return $retval;
    }

sub version_of_type {
    my $pkgtype = shift;
    return version_of_debpkg($pkgtype);
}

sub upstream_version {
    my $inver = shift;
    if ($inver =~ m/-/) {
        my @v = ($inver =~ m/^(.+)-[^-]+$/);
        return $v[0];
    }
}
            

sub getcabalname {
    my $retval = `grep ^Name *.cabal | awk '{print \$2}'`;
    chomp $retval;
    return $retval;
}

sub getcabalversion {
    my $retval = `grep ^Version *.cabal | awk '{print \$2}'`;
    chomp $retval;
    return $retval;
}

sub getcabalnameversion {
    return getcabalname() . "-" . getcabalversion();
}

sub getcabalbasepath {
    my $pkgtype = shift;
    return "/usr/lib/haskell-packages/$pkgtype";
}

sub getcabalpkglibpath {
    my $pkgtype = shift;
    return getcabalbasepath($pkgtype) . "/lib/" . getcabalnameversion();
}

sub safesystem {
    my $program = shift;
    print "Running: $program\n";
    system($program) == 0
        or die "$program files: $?";
}

print "Generating meta-information...\n";

foreach my $package (@{$dh{DOPACKAGES}}) {
	my $tmp = tmpdir($package);

        if (is_handled_package($package)) {
            my $pkgtype = type_of_package($package);
            delsubstvar($package, "haskell:Depends");
            addsubstvar($package, "haskell:Depends", 
                        $pkgtype, ">= " . upstream_version(version_of_type($pkgtype)));
            if (! ($pkgtype eq "hugs")) {
                addsubstvar($package, "haskell:Depends",
                            $pkgtype, "<< " . upstream_version(version_of_type($pkgtype)) . "-999");
            }
            
            if ($pkgtype eq "ghc5" || $pkgtype eq "ghc6") {
                # Build scripts
                my $ghcver = "ghc-" . upstream_version(version_of_type($pkgtype));
                my $pkglibdir = getcabalpkglibpath($pkgtype);
                my $cabalname = getcabalname();
                my $cabalversion = getcabalversion();

                print "$ghcver $pkglibdir $cabalname $cabalversion\n";
                autoscript($package,"postinst","postinst-ghc",
                           "s%#GHCVER#%$ghcver%;s%#PKGLIBDIR#%$pkglibdir%");
                autoscript($package,"prerm","prerm-ghc",
                           "s%#GHCVER#%$ghcver%;s%#PKGLIBDIR#%$pkglibdir%;s%#CABALNAME#%$cabalname%;s%#CABALVERSION#%$cabalversion%");
            }
        }

}

print "Building setup...\n";
safesystem("ghc6 -package Cabal Setup.lhs -o setup");

foreach my $package (@{$dh{DOPACKAGES}}) {
    my $tmp = tmpdir($package);
    if (is_handled_package($package)) {
        my $pkgtype = type_of_package($package);
        
        print "\n ****************************************** \n";
        print " NOW BUILDING $package FOR $pkgtype\n";
        print " OUTPUT TO $tmp\n\n";
        
        print "Cleaning...\n";
        system("./setup clean");
        safesystem("rm -f .*config*");
        
        if ($pkgtype eq "hugs") {
            safesystem("./setup configure --hugs");
        } else {
            safesystem("./setup configure --prefix=" . getcabalbasepath($pkgtype)
                       . " --with-compiler=/usr/bin/$pkgtype");
        }
        if ($pkgtype eq "hugs") {
            # Cabal always dies here.
            print "Running: ./setup build\n";
            system("./setup build");
            safesystem("mkdir -p $tmp/usr/lib/hugs/libraries");
            safesystem("cp -rv dist/build/* $tmp/usr/lib/hugs/libraries/");
        } else {
            safesystem("./setup build");
            safesystem("mkdir -p $tmp/usr/share/doc/$package");
            safesystem("mkdir -p $tmp" . getcabalbasepath($pkgtype));
            safesystem("./setup copy --copy-prefix=$tmp" . getcabalbasepath($pkgtype));
            safesystem("cp .installed-pkg-config $tmp" . getcabalpkglibpath($pkgtype) . "/installed-pkg-config");
        }
        print " Build for $pkgtype complete.\n";
    }
}

=head1 BUGS

hugs, ghc6, and ghc5 are the only supported targets at the moment.  Cabal does
not yet support nhc98.  Note though that there are some known bugs in
Cabal relating to ghc5 support.

=head1 SEE ALSO

L<debhelper(7)>

=head1 AUTHOR

John Goerzen <jgoerzen@complete.org>

Based on ideas in dh_python by Josselin Mouette <joss@debian.org>

=cut
