#!/usr/bin/perl

use Net::FTP;
use Fcntl;
use POSIX;
use File::stat;
# use Data::Dumper;
use IO::Handle;
# unbuffered output:
$|=1;

$ENV{'TMPDIR'} = '/var/tmp';

BEGIN{
  #
  # configurable stuff:

  # local rpm settings:
  # $rpmsourcedir = "/mnt/software/tru64/SOURCES";
  # $rpmfilepath  = "/mnt/software/tru64/RPMS";
  # $rpmarch      = "alpha";
  $rpmsourcedir = "/usr/src/packages/SOURCES";
  $rpmfilepath  = "/usr/src/packages/RPMS/Linux/SuSE-7.2";
  $rpmarch      = "i386";

  # set R_HOME=$prefix/lib/R:
  $prefix       = "/usr/local";

  push(@INC, $prefix . "/lib/R/share/perl");
}

use R::Dcf;

# ftp settings:
$cran         = "cran.r-project.org";
$contribpath  = "/pub/R/contrib/main";
# enumerate base libraries:
@baselibs=('eda','modreg','nls','stepfun','ts',
	   'ctest','lqs','mva','splines','tcltk');


# start ftp connection to CRAN:
print "initializing PACKAGES list ...\n";

$ftp = new Net::FTP($cran, Debug => 0);
unless (defined $ftp) {
  die "can't connect to server $cran";
}
unless (defined $ftp->login("anonymous",'autorpmbuilder@')) {
  die "can't login to server as anonymous";
}
unless (defined $ftp->cwd($contribpath)){
  die "can't cd to $contribpath";
}

do {
  $packagesfile = tmpnam();
} until sysopen(TMPFH, $packagesfile, O_RDWR | O_CREAT | O_EXCL, 0700);
close(TMPFH);


unless (defined $ftp->get("PACKAGES",$packagesfile)){
  die "can't download PACKAGES file";
}

open(TMPFH, $packagesfile);
#open(TMPFH, "PACKAGES");

# start parsing the PACKAGES file:
while($line=<TMPFH>){
  chomp $line;
  # find all lines starting with "Package:"
  if ($line =~ /^Package:\s*(\S+)\s*/) {
    $package=$1;
    $packages->{$package}{'Package'}=$package;
  }
}
close(TMPFH);
unlink($packagesfile);

# now parse the DESCRIPTION files:
do {
  $descriptionfile = tmpnam();
} until sysopen(TMPFH, $descriptionfile, O_RDWR | O_CREAT | O_EXCL, 0600);
close(TMPFH);

@packagenames=keys %{$packages};
foreach $package (@packagenames){
  print "processing DESCRIPTION for package $package\n";

  unless (defined $ftp->get("Descriptions/".$package.".DESCRIPTION", 
			    $descriptionfile)){
    die "can't download DESCRIPTION file for $package";
  }

  $rdcf = R::Dcf->new($descriptionfile);
  foreach $field ('Version','Description','Author','License','BundleDescription',
		  'Title','Contains','Depends','Package','URL','Date'){
    if (defined($rdcf->{$field})){
      $packages->{$package}{$field} = $rdcf->{$field};
    }
  }
}
$ftp->quit;

# now generate the spec files:

@packagenames=keys %{$packages};
foreach $package (@packagenames){
  print "processing package $package\n";

  # new ftp connection
  
  $ftp = new Net::FTP($cran, Debug => 0);
  unless (defined $ftp) {
    die "can't connect to server $cran";
  }
  unless (defined $ftp->login("anonymous",'autorpmbuilder@')) {
    die "can't login to server as anonymous";
  }
  unless (defined $ftp->cwd($contribpath)){
    die "can't cd to $contribpath";
  } 

  # prepare some rpm variables:
  @version=split(/-/,$packages->{$package}{'Version'});
  $releaseset=0;
  if (!defined($version[1])){
    $version[1]=0;
    $releaseset=1;
  }

  # use only first URL:
  if(!defined($packages->{$package}{'URL'})){
    $url="http://cran.r-project.org/contrib"
  } else {
    if($packages->{$package}{'URL'} =~ /({http:\/\/,ftp:\/\/}{\S}+)/){
      $url=$1;
    } else {
      $url="http://cran.r-project.org/contrib"
    }
  }
  if(($packages->{$package}{'License'})){
    $license="unknown";
  } else {
    $license=$packages->{$package}{'License'};
  }

  # collect dependencies:
  $requires = "R-base";
  if(defined($packages->{$package}{'Depends'})){
    foreach $otherpackage (@packagenames) {
      if($package!=$otherpackage){
	if($packages->{$package}{'Depends'} =~ /$otherpackage/){
	  $requires = $requires . " R-" . $otherpackage;
	}
      }
    }
# not necessary because all base libs are in R-base!
# maybe later, if the R-base package gets split?
#    foreach $otherpackage (@baselibs) {
#      if($packages->{$package}{'Depends'} =~ /$otherpackage/){
#	$requires = $requires . " R-" . $otherpackage;
#      }
#    }
  }

  # prepare filenames:
  $sourcefile = $packages->{$package}{'Package'} . "_" . 
    $packages->{$package}{'Version'}  . ".tar.gz";
  $rpmfile = $rpmfilepath . "/" . $rpmarch . "/R-" 
    .$packages->{$package}{'Package'} . "-" . 
    $version[0] . "R" . $version[1]  . "-1." . $rpmarch . ".rpm";

  $ftp->binary();
  $download = $rpmsourcedir . "/" . $sourcefile;

  # rpm already built?
  $downloadstat=stat($download);
  $mustdownload=0;
  if($downloadstat){
    $mtime=$ftp->mdtm($sourcefile);
    unless (defined $mtime){
      # ftp timeout?
      warn "can't get mtime of ftp file $sourcefile";
      $mustdownload=0;
    } else {
      if($downloadstat->mtime < $mtime){
	print "ftp file newer, going to download $sourcefile...\n";
	$mustdownload=1;
      }
      else {
	$size=$ftp->size($sourcefile);
	unless (defined $size){
	  # ftp timeout?
	  warn "can't get size of ftp file $sourcefile";
	  $mustdownload=0;
	} else {
	  if($downloadstat->mtime >= $mtime and $downloadstat->size!=$size) {
	    print "ftp file differs in size, going to download $sourcefile...\n";
	    $mustdownload=1;
	  }
	}
	warn "already downloaded!\n";
      }
    }
  } else {
    $mustdownload=1
  }

  $generatespec=1;

  if($mustdownload==1) {
    print "downloading $sourcefile...\n";
    unless (defined $ftp->get($sourcefile, $download)){
      warn "can't download $sourcefile file";
      $generatespec=0;
    }
  }

  $specfile = "R-" . $packages->{$package}{'Package'} . "-"
    . $packages->{$package}{'Version'} . ".spec";

  if(stat($specfile)){
    if(stat($rpmfile)){
      if(stat($specfile)->mtime > stat($rpmfile)->mtime){
	$generatespec=0;
      }
    }
  }
  
  if(defined($packages->{$package}{'Contains'})){
    @subpackages=split(/\s+/,$packages->{$package}{'Contains'});
  }
  
  if($generatespec==1){
    if(stat($specfile)){
      system("mv $specfile $specfile.bak");
      warn "backup of $specfile created!\n";
    }
    sysopen(SPECFH, $specfile , O_RDWR | O_CREAT | O_ECXL, 0644) 
      or die "cannot open spec file";
    print "generating specfile ...\n";
    print SPECFH <<EOT
########## automatically generated by build-contrib-rpms.pl ####################
# spec file for R library $packages->{$package}{'Package'}
#
# A. Gebhardt <albrecht.gebhardt\@uni-klu.ac.at>
#
%define ver      $version[0]
%define packrel  $version[1]
%define rel      1
%define packname $packages->{$package}{'Package'}
%define prefix   $prefix

Name: R-%{packname}
Version: %{ver}.R%{packrel}
Release: %{rel}
EOT
;
    if($releaseset==0){
      print SPECFH <<EOT
Source: ftp://cran.r-project.org/pub/R/contrib/main/%{packname}_%{ver}-%{packrel}.tar.gz
EOT
;
    } else {
      print SPECFH <<EOT
Source: ftp://cran.r-project.org/pub/R/contrib/main/%{packname}_%{ver}.tar.gz
EOT
;
    }
      print SPECFH <<EOT
Copyright: $license
URL: $url
Group: Applications/Math
Summary: R package %{packname} - $packages->{$package}{'Title'}
BuildRequires: R-base
PreReq: R-base
Requires: $requires
BuildRoot: /var/tmp/%{packname}-buildroot

EOT
;
    if(!defined($packages->{$package}{'Contains'})){
      print SPECFH <<EOT
%description
R package:
$packages->{$package}{'Description'}
EOT
;
    } else {
      print SPECFH <<EOT
%description
R package bundle:
$packages->{$package}{'BundleDescription'}
EOT
;
    }
    print SPECFH <<EOT

Author(s)
$packages->{$package}{'Author'}

$packages->{$package}{'Date'}
%prep
%setup -T -c -a 0

%build
cp %{packname}/DESCRIPTION .

%install
rm -rf \$RPM_BUILD_ROOT
mkdir -p \$RPM_BUILD_ROOT%{prefix}/lib/R/library
%{prefix}/bin/R INSTALL -l \$RPM_BUILD_ROOT%{prefix}/lib/R/library %{packname}
%{prefix}/bin/R CMD check %{packname}
EOT
;
    if(!defined($packages->{$package}{'Contains'})){
      print SPECFH <<EOT
test -d %{packname}/src && (cd %{packname}/src; rm -f *.o *.so)
EOT
;
    } else {
      foreach $subdir (@subpackages){
	print SPECFH <<EOT
test -d %{packname}/$subdir/src && (cd %{packname}/$subdir/src; rm -f *.o *.so)
EOT
;
      }
    }
    print SPECFH <<EOT


%clean
rm -rf \$RPM_BUILD_ROOT

%post
%{prefix}/bin/R CMD perl %{prefix}/lib/R/share/perl/build-help.pl --htmllists
cat %{prefix}/lib/R/library/*/CONTENTS > %{prefix}/lib/R/doc/html/search/index.txt

%postun
%{prefix}/bin/R CMD perl %{prefix}/lib/R/share/perl/build-help.pl --htmllists
cat %{prefix}/lib/R/library/*/CONTENTS > %{prefix}/lib/R/doc/html/search/index.txt

%files
%doc DESCRIPTION
EOT
;
    if(!defined($packages->{$package}{'Contains'})){
      print SPECFH <<EOT
%{prefix}/lib/R/library/%{packname}
EOT
;
    } else {
      foreach $subdir (@subpackages){
	print SPECFH <<EOT
%{prefix}/lib/R/library/$subdir
EOT
;
      }
    }
    print SPECFH <<EOT


####### end of spec-file ################################################
EOT
;

    close(SPECFH);
  }

  $ftp->quit;

  if(!stat($rpmfile) && stat($specfile) && stat($download)){
    system("rpm -ba $specfile");
  }
}




# print a summary:
foreach $package (@packagenames){
  print "checking for package $package ...";
  @version=split(/-/,$packages->{$package}{'Version'});
  $releaseset=0;
  if (!defined($version[1])){
    $version[1]=0;
    $releaseset=1;
  }
  $rpmfile = $rpmfilepath . "/" . $rpmarch . "/R-" . 
    $packages->{$package}{'Package'} . "-" . 
    $version[0] . ".R" . $version[1]  . "-1." . $rpmarch . ".rpm";
  if(stat($rpmfile)){
    print "exists.\n";
  }
  else {
    print "failed!\n";
  }
}
