#!/usr/bin/perl
# 
# cpan2tgz - create slackware packages from cpan distributions 
# 
# Jason Woodward
# woodwardj at jaos dot org
# http://software.jaos.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
# 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 Library 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.
#
#use strict;
use warnings;
use Config;
use Getopt::Long;
use File::Find ();
use Errno;

our $VERSION = '0.6.8';

$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
my (
    %PACKAGE_CACHE_LIST,        $no_recursive,
    $no_install_after_building, $ignore_installed_deps,
    $tmp_dir,                   $package_dir,
    $nobanner,                  $upgrade_all,
    $build_tag,                 $build_number,
    $pkgext,
);
$tmp_dir      = "$ENV{TMP}";
if($tmp_dir eq "") {
  $tmp_dir      = "/tmp";
}
#$package_dir  = "/usr/src/";
#$package_dir  = "/root/compile/Perl";
$package_dir = $tmp_dir;
$package_dir  = "$ENV{PACKAGE_DIR}" if(defined($ENV{PACKAGE_DIR}));
if($package_dir eq "")
{
  $package_dir=$tmp_dir;
}
$build_number = shift || 1;
$build_tag = "";
$pkgext       = 'txz';


sub do_package
{

  my $pack;

  # try to extract some info about the module
  $pname=`pwd`;
  chop($pname);
  if(($i=rindex($pname,"/"))>0)
  {
    $pname=substr($pname,$i+1);
  }
  $ver="0";
  if(($i=rindex($pname,"-"))>0)
  {
    $ver=substr($pname,$i+1);
    $pname=substr($pname,0,$i);
  }
  my $pkg_name = "perl-$pname";
  my $final_pkg_version = $ver;
  my $final_pkg_name = $pkg_name;
  my $module_name = $pname;

  $pkg_name.="-$ver";

  # figure out the arch of the package, default to noarch
  my @xs_files = ();
  File::Find::find( sub { /^.*\.(?:xs|c|h|so)\z/s && push @xs_files, $_; }, ".");
  if ( @xs_files ) {
    $pkg_name .= "-" . [split('-',$Config{archname})]->[0];
  } else {
    $pkg_name .= "-noarch";
  }
  $pkg_name .= "-${build_number}${build_tag}.${pkgext}";

  my $dest_dir = $tmp_dir . '/' . $final_pkg_name;

  print "\n\nProcessing $module_name...\n\n";

  if($Config{archname}=~m/x86_64/) { $libsuffix="64"; }
  else { $libsuffix=""; }


  # do an initial make so that we can get the dep info
  $jobs=$ENV{NUMJOBS};
  if(!defined($jobs)) { $jobs=""; }
  if(-f "Makefile.PL")
  {
    system("perl Makefile.PL SITEPREFIX=/usr SITELIBEXP=/usr/share/perl5 SITEARCHEXP=/usr/lib$libsuffix/perl5 INSTALLSITELIB=/usr/share/perl5 INSTALLSITEARCH=/usr/lib$libsuffix/perl5 INSTALLSITEBIN=/usr/bin INSTALLSITESCRIPT=/usr/bin INSTALLSITEMAN1DIR=/usr/share/man/man1 INSTALLSITEMAN3DIR=/usr/share/man/man3 \&\& make $jobs");
  }
  elsif(-f "Build.PL")
  {
    system("perl Build.PL --config siteprefix=/usr --config sitelibexp=/usr/share/perl5 --config sitearchexp=/usr/lib$libsuffix/perl5 --config installsitelib=/usr/share/perl5 --config installsitearch=/usr/lib$libsuffix/perl5 --config installsitebin=/usr/bin --config installsitescript=/usr/bin --config installsiteman1dir=/usr/share/man/man1 --config installsiteman3dir=/usr/share/man/man3 \&\& ./Build");
  }
  else {
    print "Cannot find build scripts (Makefile.PL or Build.pl). Aborting\n";
    exit(1);
  }

  if($@) 
  {
    # use and $! is set to an internal non-fatal value from a YAML
    # check
      print "make ERROR [$module_name]: $!\n";
      exit(1);
  }

  clear_build_dir($dest_dir);
  
  # here we do steps to cleanup source before we build (per LinuxPackages.net perfect packages instructions)
  # this isn't pretty but it gets the job done
  my $pack_dir = $dest_dir;

  if ( -f "Build" ) {
    system("./Build install --destdir=$dest_dir");
  } else {
    system("make install DESTDIR=$dest_dir");
  }

  system("cd $pack_dir && chown -R root.root .");
  system("cd $pack_dir && find . -perm 777 -exec chmod 755 {} \\;");
  system("cd $pack_dir && find . -perm 555 -exec chmod 755 {} \\;");
  system("cd $pack_dir && find . -perm 444 -exec chmod 644 {} \\;");
  system("cd $pack_dir && find . -perm 666 -exec chmod 644 {} \\;");
  system("cd $pack_dir && find . -perm 664 -exec chmod 644 {} \\;");

  # install to the package build dir
  die "Failed to install to $dest_dir: $!" unless (-d $dest_dir);

  # copy documentation to the package build dir
  system("cd $dest_dir && mkdir -p ./usr/doc/$final_pkg_name");
  system("find . -type f -iregex '.*readme.*' -o -iregex '.*change.*' -o -iregex '.*todo.*' -o -iregex '.*license.*' -o -iregex '.*copying.*' -o -iregex '.*install.*' -o -iregex '.*\.txt' -o -iregex '.*\.html' |xargs -r -iZ cp Z $dest_dir/usr/doc/$final_pkg_name" . "/");

  # build a shell script to fixup the package like Pat's Perl SlackBuild
  open(my $script_fh,">$dest_dir/build.sh") or die "Failed to open build.sh for writing: $!";
  print $script_fh "cd $dest_dir\n";
  print $script_fh "find . | xargs file | grep 'executable' | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null\n";
  print $script_fh "find . | xargs file | grep 'shared object' | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null\n";
  print $script_fh "find ./usr/share/man/ -name '*.3' -exec gzip -9 {} \\; 2> /dev/null\n";
  print $script_fh "find ./usr/share/man/ -name '*.1' -exec gzip -9 {} \\; 2> /dev/null\n";
  print $script_fh "mv ./usr/share/man ./usr/\n" if (-d "$dest_dir/usr/share/man");
  print $script_fh "chown -R `stat --format '%u:%g' /usr/bin` ./usr/bin\n" if (-d "$dest_dir/usr/bin");
  print $script_fh "chmod 755 ./usr/bin/*\n" if (-d "$dest_dir/usr/bin");
  print $script_fh "chmod 644 ./usr/man/man?/*\n" if (-d "$dest_dir/usr/man");
  print $script_fh "rmdir ./usr/share\n" if (-d "$dest_dir/usr/share");
  print $script_fh "mkdir ./install\n";

  # generate the doinst.sh to fix perllocal.pod
  print $script_fh <<SCRIPT
PERLLOCALPOD=\`find . -name perllocal.pod\`
if [ -n "\$PERLLOCALPOD" ]; then
  cat >./install/doinst.sh <<EOF
#!/bin/sh

cat >> \${PERLLOCALPOD/.\\//} <<PLP

EOF
  cat \$PERLLOCALPOD >>install/doinst.sh
  echo "PLP" >>install/doinst.sh
  rm \$PERLLOCALPOD
fi
SCRIPT
;

  close($script_fh);
  system("cd $dest_dir && sh build.sh");
  system("cd $dest_dir && rm build.sh");

  
  # generate the slack-desc file
  open(my $desc_fh,">$dest_dir/install/slack-desc") or die "Failed to open slack-desc for writing: $!";
  print $desc_fh "\n";
  print $desc_fh "# HOW TO EDIT THIS FILE:\n";
  print $desc_fh "# The \"handy ruler\" below makes it easier to edit a package description.  Line\n";
  print $desc_fh "# up the first '|' above the ':' following the base package name, and the '|'\n";
  print $desc_fh "# on the right side marks the last column you can put a character in.  You must\n";
  print $desc_fh "# make exactly 11 lines for the formatting to be correct.  It's also\n";
  print $desc_fh "# customary to leave one space after the ':'.\n";
  print $desc_fh "\n";
  print $desc_fh "         |-----handy-ruler------------------------------------------------------|\n";
  print $desc_fh "$final_pkg_name: $final_pkg_name " . $ver . " (Perl module)\n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  \n";
  print $desc_fh "$final_pkg_name:  Packaged by perl2tgz\n" unless $nobanner;
  print $desc_fh "$final_pkg_name:  based on cpan2tgz by Jason Woodward <woodwardj\@jaos.org>\n" unless $nobanner;
  print $desc_fh "$final_pkg_name:  http://software.jaos.org/\n" unless $nobanner;
  print $desc_fh "$final_pkg_name:  \n";
  close($desc_fh);

  # finally, build the package
  system("cd $dest_dir && makepkg -l y -c n $package_dir/$pkg_name");
  die "Failed to build package $pkg_name: $!" unless (-f "$package_dir/$pkg_name");

  # install the package
  #unless ($no_install_after_building) {
  #  system("installpkg $package_dir/$pkg_name") && exit;
  #}

  clear_build_dir($dest_dir);

  return $final_pkg_name;
}

sub clear_build_dir
{
  my ($dest_dir) = @_;
  return unless $dest_dir;
  system("rm -r $dest_dir/*") if (-d $dest_dir);
  system("rmdir $dest_dir") if (-d $dest_dir);
}

do_package(@ARGV);
