#!/usr/bin/perl

=head1 NAME

dh_elpa - install emacs lisp packages into package build directories

=cut

use strict;
use Cwd qw{ getcwd };
use File::Temp qw{tempfile};
use IO::Handle;
use File::Path;

use Debian::Debhelper::Dh_Lib;

=head1 SYNOPSIS

B<dh_elpa> [S<I<debhelper options>>]  [S<I<pkg-file>>]

=head1 DESCRIPTION

B<dh_elpa> is a debhelper program that is responsible for installing
elpa style emacs lisp packages into package build directories.

=head1 FILES

=over 4

=item debian/I<package>.elpa

List of files to be installed into I<package> as an elpa package.

=back

=cut

init(options => {
	"byte-compile!" => \$dh{BYTECOMPILE},
});

=head1 OPTIONS

=over 4

=item B<--byte-compile>, B<--no-byte-compile>

Enable (default) or disable byte compilation of installed emacs lisp
files.  Disabling byte compilation changes the destination directory
to one that is found by the emacs package system.

=back

=cut

sub doit_quietly {
  my ($handle,$tmpfile) = tempfile(UNLINK=>1);
  my $exitcode;

  verbose_print(escape_shell(@_));
  open (CPERR,">&STDERR") or error "$!";
  open (CPOUT,">&STDOUT") or error "$!";
  STDOUT->fdopen($handle,'w');
  STDERR->fdopen($handle,'w');
  my $ret=doit_noerror(@_);
  STDOUT->fdopen(\*CPOUT,'w');
  STDERR->fdopen(\*CPERR,'w');

  if (!$ret){
    $exitcode=$?;
    seek $handle, 0, 0 or error "$!";
    print while (<$handle>);
    my $command=join(" ",@_);
    error("$command returned exit code ".($exitcode >> 8));
  }

}

# simplified version of private sub autoscript_sed in Dh_Lib
sub sed_file {
  my ($sed, $infile, $outfile) = @_;

  open(IN, $infile) or die "$infile: $!";
  open(OUT, ">>$outfile") or die "$outfile: $!";
  while (<IN>) { $sed->(); print OUT }
  close(OUT) or die "$outfile: $!";
  close(IN) or die "$infile: $!";
}

sub read_package_desc {
  my ($descdir, $package) = @_;
  my %desc = ();

  my $descfile="${descdir}/${package}.desc";

  my $fh;

  open $fh,'<', $descfile or
    error "failed to open $descfile";

  while (<$fh>) {
    if (m/([^:]+):\s*(.*)\s*$/) {
      $desc{$1} = $2;
    }
  }
  return \%desc;
}

my $templatedir = "/usr/share/debhelper/dh_elpa/emacsen-common";

sub maybe_install_helper{
  my ($package,$piece, $mode, $desc)=@_;
  my $file=pkgfile($package,"emacsen-$piece");

  my $tmp=tmpdir($package);
  my $ecdest="$tmp/usr/lib/emacsen-common/packages";
  my $target="$ecdest/$piece/$package";
  # if there is file, leave it for dh_installemacsen
  if ($file eq '') {
    if (! -d "$ecdest/$piece") {
      doit("install","-d","$ecdest/$piece");
    }
    unlink $target; # ignore errors

    my $elpapackage = $desc->{'ELPA-Name'} or
      error "elpa package name not found";

    my $elpaversion = $desc->{'ELPA-Version'} or
      error "elpa version not found";

    sed_file (sub {s/#ELPAPACKAGE#/$elpapackage/;
		   s/#ELPAVERSION#/$elpaversion/; },
	      "$templatedir/$piece", $target);
    chmod oct($mode), $target;
  }
}

$dh{BYTECOMPILE} = 1 unless defined($dh{BYTECOMPILE});

my $elpadir;

my $dhelpadir="/usr/share/emacs/site-lisp/elpa";

# TODO: do we really need a seperate elpa-src hierarchy?
if ($dh{BYTECOMPILE}) {
  $elpadir="/usr/share/emacs/site-lisp/elpa-src";
} else {
  $elpadir=$dhelpadir;
}

PACKAGE:
foreach my $package (@{$dh{DOPACKAGES}}) {

  my $tmp=tmpdir($package);
  my $file=pkgfile($package,"elpa");

  my $elpapkg=$package;
  # TODO do this more sanely or at least allow an override
  $elpapkg =~ s/^elpa-//;
  verbose_print("Using elpa package name $elpapkg");

  my @files;

  # Call isnative because it sets $dh{VERSION}
  # as a side effect.
  isnative($package);
  if ($file) {
    @files=filearray($file, ".");
    scalar(@files) == 1 || grep { m/\b${elpapkg}-pkg.el$/ } @files or
      error "missing ${elpapkg}-pkg.el";
  }
  if (($package eq $dh{FIRSTPACKAGE} || $dh{PARAMS_ALL})
      && @ARGV) {
    push @files, @ARGV;
  }

  next PACKAGE if (scalar(@files) == 0);

  my $pkg_file;
  my $cwd = getcwd();
  my $tempdir = "${cwd}/debian/.debhelper/elpa";

  File::Path::rmtree $tempdir ||
      error "cleaning $tempdir";

  File::Path::make_path $tempdir ||
	  error "creating $tempdir";

  if (scalar(@files) == 1) {
      my $pkg_file=$files[0];

      doit_quietly(qw{emacs -batch -Q -l package},
		   '--eval',"(add-to-list 'package-directory-list \"$dhelpadir\")",
		   '--eval',"(add-to-list 'package-directory-list \"$elpadir\")",
		   qw{-f package-initialize -l dh-elpa.el},
		   qw{-f dhelpa-batch-install-file}, "$tmp/$elpadir", $pkg_file, $tempdir);
  } else {
    my $stagedir = "$tempdir/$elpapkg";
    File::Path::make_path $stagedir ||
	  error "creating $stagedir";

    # copy files into stagedir, flattening hierarchy
    # TODO: do this more correctly
    foreach my $el_file (@files) {
      doit("cp", "-a", $el_file, "$stagedir");
    }

    doit_quietly(qw{emacs -batch -Q -l package},
		 '--eval',"(add-to-list 'package-directory-list \"$dhelpadir\")",
		 '--eval',"(add-to-list 'package-directory-list \"$elpadir\")",
		 qw{-f package-initialize -l dh-elpa.el},
		 qw{-f dhelpa-batch-install-directory},
		 "$tmp/$elpadir", $stagedir, $tempdir);

  }
  if ($dh{BYTECOMPILE}) {
    my $desc = read_package_desc ($tempdir,$elpapkg);

    addsubstvar($package,'misc:Depends','emacsen-common');
    maybe_install_helper($package, 'compat', '0644', $desc);
    maybe_install_helper($package, 'install', '0755', $desc);
    maybe_install_helper($package, 'remove', '0755', $desc);

    if (! $dh{NOSCRIPTS}) {
      autoscript($package,"postinst","postinst-emacsen",
                 "s/#PACKAGE#/$package/");
      autoscript($package,"prerm","prerm-emacsen",
                 "s/#PACKAGE#/$package/");
    }
  }

}

=head1 EXAMPLES

Here is an example of using the helper in a dh(1) style debian/rules

=over 4

override_dh_install:
        dh_install
        dh_elpa

=back

=cut

