#!/usr/bin/perl -w

# Copyright 2021, 2022 Kevin Ryde

# This file 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, or (at your option) any later
# version.
#
# This file 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 file.  If not, see <http://www.gnu.org/licenses/>.


# Usage: perl make-opt-pari-deb pari-2.9.5.tar.gz
#
# For a given PARI/GP source .tar.gz file, make a Debian package
# "opt-pari-2.9.5-gp" such as (in whatever arch instead of i386),
#
#     opt-pari-2.9.5-gp_2.9.5-1_i386.deb
#
# The build and resulting deb are made in a subdirectory,
#
#     make-opt-pari-deb-build/
#
# The deb can be made by any user since code here uses fakeroot for the
# build, but installing the deb will need root in the usual way.
#
# PARI Configure options are in the debian/rules file generated below.
# --with-graphic=none is set expecting that a past GP will be used just to
# exercise code compatibility rather than any actual work where ploth() etc
# graphics might be desirable.
#
# A PARI daily snapshot ought to work, provided the source dist name is like
# pari-XXX.tar.gz and it contains within it a directory pari-XXX/...
#
# Requirements
# ------------
#
# Needs cdbs, debhelper, libgmp-dev, libreadline-dev.
#
# Package Contents
# ----------------
#
# In the package made, the GP interpreter is ready to run
#
#     /usr/bin/gp-2.9.5
#
# This static linked, so no separate libpari.  This can co-exist with other
# versions and whatever current PARI/GP package "pari-gp" (which is a static
# link too, circa its version 2.13).
#
# The package install is under a tree /opt/pari-2.9.5/,
#
#     /opt/pari-2.9.5/bin/gp
#     /opt/pari-2.9.5/etc/
#     /opt/pari-2.9.5/share/man/man1/
#     etc
#
# Then symlinks in /usr/bin/ and /usr/share/man/man1/ point into that tree
# to have executable (and man page) gp-2.9.5.
#
# The GP binary refers to a few config things and directories under its
# target tree, so keeping that in one place is good, rather than trying to
# spread out versioned files through the normal directories.  Strictly
# speaking, /opt/pari-2.9.5/etc/ should be /opt/etc/pari-2.9.5/, but that's
# more trouble than it's worth.
#
# Currently documentation is omitted from the deb.  GP has a 1-line summary
# of each function with say ?nfeltpow, but the equivalent ??nfeltpow to
# display the section of the manual is not available.
#
# Environment Variables
# ---------------------
#
# DEBFULLNAM
# DEBEMAIL
#     If set, then these are the maintainer name and email put into in the
#     package control file (like dh-make-perl does).  The default maintainer
#     name is current user real name from /etc/passwd file GECOS, and just
#     username@localhost email.
#
# Other Ways To Do It
# -------------------
#
# PARI "./Configure" and "make gp" is simple and the resulting gp will run
# from the build directory.  Putting it in a deb has the advantage of
# declaring dependencies on library packages used (eg. the version of
# readline), keeping only as much of the build as needed, and is easy to
# "dpkg --purge" later.
#
# Things Not Done
# ---------------
#
# PARI has a few build options which might be desirable but are not offered
# here (beyond modifying the Configure invocation in the code below).
# Options which affect capabilities might like to be in the package name and
# executable gp program name so they can co-exist with a plain build.
#
# Changes
# -------
# Version 1 - the first version.
#

use 5.010;
use strict;
use Cwd;
use File::Path;
use File::Slurp 9999.14;  # 9999.14 for write_file() perms=>..
use File::Spec;
use File::Remove;
use FindBin;
use POSIX ();
$|=1;

our $VERSION = 1;

my $builddir = 'make-opt-pari-deb-build';
my $userfullname = notempty($ENV{'DEBFULLNAME'})
  // do {
    my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell, $expire) = getpwuid($<);
    $gcos =~ s/,.*//;
    notempty($gcos)
  }
  // 'Nobody';
my $email = notempty($ENV{'DEBEMAIL'})
  // (notempty($ENV{'USER'}) // notempty($<) // 'root') . "\@localhost";
my $orig_dir     = Cwd::getcwd();
use constant STRFTIME_FORMAT_RFC822 => '%a, %d %b %Y %H:%M:%S %z';
my $datetime = POSIX::strftime(STRFTIME_FORMAT_RFC822, localtime(time()));

print "userfullname:      $userfullname\n";
print "email:             $email\n";
print "builddir:          $builddir\n";

unless (@ARGV) {
  print "No .tar.gz files given to build.\n";
  exit 0;
}

File::Path::make_path($builddir);
$builddir = File::Spec->rel2abs($builddir);

foreach my $tarfilename (@ARGV) {
  print "chdir to builddir: $builddir\n";
  chdir $builddir or die "Cannot chdir to $builddir: $!";

  $tarfilename =~ m{(/|^)pari-([0-9a-zA-Z.-]+)\.tar\.gz$}
    or die "tar filename format unrecognised: $tarfilename";
  my $version = $2;
  my $dirname = "pari-$version";
  if (-e $dirname) {
    print "remove old:       $builddir/$dirname\n";
    File::Remove::remove(\1, $dirname);
    if (-e $dirname) { die "oops, not removed"; }
  }

  my $full_tarfilename = File::Spec->rel2abs($tarfilename, $orig_dir);
  print "untar from $full_tarfilename\n";
  my $gzipz = ($full_tarfilename =~ /\.gz$/ ? 'z' : '');
  system('tar', "xf$gzipz", $full_tarfilename) == 0 or die;

  print "chdir to $builddir/$dirname\n";
  chdir "$builddir/$dirname" or die;
  File::Path::make_path('debian/source');

  File::Slurp::write_file('debian/compat',"9\n");
  File::Slurp::write_file('debian/source/format',"1.0\n");

  #------------
  File::Slurp::write_file('debian/changelog', <<"HERE");
opt-pari-$version ($version-1) unstable; urgency=low

  * Packaged version.

 -- $userfullname <$email>  $datetime
HERE

  #------------
  File::Slurp::write_file('debian/control',<<"HERE");
Source: opt-pari-$version
Section: math
Priority: optional
Build-Depends: perl (>= 5.6), cdbs, debhelper (>= 9), libgmp-dev, libreadline-dev
Maintainer: $userfullname <$email>
Standards-Version: 4.2.1
Homepage: http://pari.math.u-bordeaux.fr
Bugs: mailto:$email

Package: opt-pari-$version-gp
Architecture: any
Depends: \${misc:Depends}, \${shlibs:Depends}
Description: PARI/GP $version GP interpreter
 Semi-automatically generated by $FindBin::Script.
HERE

  #------------
  File::Slurp::write_file('debian/copyright',<<"HERE");
PARI/GP is Copyright the several authors and contributors in

    /usr/share/doc/opt-pari-$version-gp/AUTHORS.gz

and is distributed under the GNU General Public License (GPL)
version 2.  The complete text of GPL version 2 is in the file

    /usr/share/common-licenses/GPL-2
HERE

  #------------
  File::Slurp::write_file('debian/rules', {perms=>0777}, <<"HERE");
#!/usr/bin/make -f

# PARI Configure is not quite autoconf/automake style, but close enough to
# allow cdbs autotools.mk.  Several args which cdbs puts into
# DEB_CONFIGURE_NORMAL_ARGS are not accepted by Configure, so replace with
# as much as is accepted.

export DEB_BUILD_MAINT_OPTIONS=hardening=+all

include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/autotools.mk

# In PARI prior to 2.9.x, Perl script src/desc/merge_822 picked up its
# PARI::822 helper module by expecting Perl to have "." in the \@INC, which
# is no longer so.  Hack PERL5LIB to include the desired directory.
#
export PERL5LIB=\$(PWD)/src/desc

DEB_CONFIGURE_PREFIX    = /opt/pari-$version
DEB_CONFIGURE_SCRIPT    = ./Configure
DEB_CONFIGURE_NORMAL_ARGS = \\
  --prefix=\$(DEB_CONFIGURE_PREFIX) \\
  --graphic=none \\
  --static \\
  --with-gmp \\
  --with-readline

DEB_MAKE_BUILD_TARGET   = gp
DEB_MAKE_INSTALL_TARGET = install-bin DESTDIR=\$(DEB_DESTDIR)

install/opt-pari-$version-gp::
	# source directory Makefile no "install-man",
	# must switch to the objdir build
	cd `config/objdir` && make install-man DESTDIR=\$(DEB_DESTDIR)
HERE

  #------------
  File::Slurp::write_file('debian/links',<<"HERE");
opt/pari-$version/bin/gp              usr/bin/gp-$version
opt/pari-$version/share/man/man1/gp.1 usr/share/man/man1/gp-$version.1
HERE

  #------------
  File::Slurp::write_file('debian/dirs',<<"HERE");
opt/pari-$version/etc/
HERE

  #------------
  system('ls', '-ld', glob("$builddir/$dirname/debian/*"));
  print "\n";
  system('fakeroot', 'debian/rules', 'binary') == 0 or die;
  system("ls -l $builddir/opt-pari-$version*.deb");
}

exit 0;

sub notempty {
  my ($str) = @_;
  if (! defined $str || $str eq '') { return undef; }
  return $str;
}
