#!/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},
	"fix-autoload-date!" => \$dh{FIXAUTOLOADDATE},
});

=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

=over 4

=item B<--fix-autoload-date>, B<--no--fix-autoload-date>

Enable (default) or disable munging the dates in Emacs generated
autoload files to match debian/changelog.

=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});
$dh{FIXAUTOLOADDATE} = 1 unless defined($dh{FIXAUTOLOADDATE});

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
      warning "missing ${elpapkg}-pkg.el; will try to generate it";
  }
  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";
  my $helper_version = '0.0.19';

  my @extra_args = ( $tempdir );

  if ($dh{FIXAUTOLOADDATE}) {
    push @extra_args, get_source_date_epoch();
  }

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

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

  addsubstvar($package,'misc:Built-Using',"dh-elpa (= ${helper_version})");

  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, @extra_args);
  } 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, @extra_args);

  }

  my $desc = read_package_desc ($tempdir,$elpapkg);
  my $deps = $desc->{'ELPA-Requires'};

  # TODO: addsubstvar fails to add a variable if its blank.  So if the
  # package has no ELPA dependencies, we should tell the user not to
  # use this substvar in debian/control
  addsubstvar($package, 'elpa:Depends', $deps);

  if ($dh{BYTECOMPILE}) {
    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 SUBSTVARS

dh_elpa currently defines three substvars (cf. deb-substvars(5)) that
can be used in debian/control

=over 4

=item ${misc:Depends}

These are dependencies needed by every dh_elpa based package.

=item ${misc:Built-Using}

This adds a value suitable for a Built-Using header identifying the
version of dh_elpa used at build time.

=item ${elpa:Depends}

These are dependencies on other ELPA packages as given in the
Package-Requires: line of the package's main Emacs Lisp file.

Note that Emacs Lisp dependencies packaged outside the elpa-* dpkg
namespace must be specified manually.  For example, the s.el library
is provided by the binary package s-el.  If dh_elpa adds dependency
elpa-x where x is an Emacs Lisp binary package outside the elpa-*
namespace, please file a bug against dh_elpa to have an exclusion
added.

=back

=head1 EXAMPLES

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

=over 4

    #!/usr/bin/make -f
    %:
        dh $@ --with elpa

=back

Here is an example of a binary package stanza using dh_elpa generated
substvars

=over 4

    Package: elpa-hello
    Architecture: all
    Depends: ${misc:Depends}, ${elpa:Depends}
    Built-Using: ${misc:Built-Using}
    Description: Emacs addon to say hello
     The Emacs editor addon likes to wave and say hello.

=back

=cut

