#! @PERL@ #-*- perl -*- # Copyright (C) 2000, 2001 R Development Core Team # # 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, or (at your option) # 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 # General Public License for more details. # # A copy of the GNU General Public License is available via WWW at # http://www.gnu.org/copyleft/gpl.html. You can also obtain it by # writing to the Free Software Foundation, Inc., 59 Temple Place, # Suite 330, Boston, MA 02111-1307 USA. # Send any bug reports to r-bugs@r-project.org use Cwd; use File::Basename; use File::Compare; use File::Find; use File::Path; use Getopt::Long; use R::Dcf; use R::Utils; use R::Rd; #use strict; ## don't buffer output $|=1; my $revision = ' $Revision: 1.25 $ '; my $version; my $name; $revision =~ / ([\d\.]*) /; $version = $1; ($name = $0) =~ s|.*/||; $make = '@MAKE@'; my @knownoptions = ("help|h", "version|v", "binary", "no-docs", "use-zip", "use-zip-help", "use-zip-data", "force"); my $WINDOWS = (R_getenv("R_OSTYPE", "") eq "windows"); my $tmpdir = R_getenv("TMPDIR", "/tmp"); my $R_exe = "${R_HOME}/bin/R"; if($WINDOWS){ $tmpdir = R_getenv("TMPDIR", "/TEMP"); die "Please set TMPDIR to a valid temporary directory\n" unless (-e $tmpdir); $R_exe = "Rterm.exe"; $MAKE = "make"; @knownoptions = ("help|h", "version|v", "binary", "docs:s", "use-zip", "use-zip-help", "use-zip-data", force); } GetOptions (@knownoptions) || usage(); R_version("R add-on package builder", $version) if $opt_version; usage() if $opt_help; my $startdir=cwd(); my $R_platform = R_getenv("R_PLATFORM", "unknown-binary"); my $R_HOME = $ENV{'R_HOME'} || die "Error: Environment variable R_HOME not found\n"; my $R_CMD = $ENV{'R_CMD'} || die "Error: Environment variable R_CMD not found\n"; my $INS_opts = ""; $INS_opts .= " --use-zip" if $opt_use_zip; $INS_opts .= " --use-zip-data" if $opt_use_zip_data; $INS_opts .= " --use-zip-help" if $opt_use_zip_help; if($WINDOWS) { $INS_opts .= " --docs=$opt_docs" if $opt_docs; } else { $INS_opts .= " --no-docs" if $opt_no_docs; } if(!$opt_binary && $INS_opts ne "") { printf "** Options $INS_opts for --binary ignored\n"; } ## this is the main loop over all packages to be checked my $pkg; foreach $pkg (@ARGV){ my $is_bundle=0; $pkg =~ s/\/$//; my $pkgname = basename($pkg); chdir($startdir); my $log = new R::Logfile(); my $description; $log->checking("for file \`$pkg/DESCRIPTION'"); if(-r "$pkg/DESCRIPTION"){ $description = new R::Dcf("$pkg/DESCRIPTION"); $log->result("OK"); } else{ $log->result("NO"); exit(1); } if($opt_binary){ my $libdir = "$tmpdir/Rbuild.$$"; mkdir("$tmpdir/Rbuild.$$", 0755) || die "Cannot create directory $tmpdir/Rbuild.$$\n"; if(system("$R_CMD INSTALL -l $libdir $INS_opts $pkg")){ $log->error("installation failed"); } print("\n"); chdir($libdir); my $pkgs = $pkgname; if($description->{"Contains"}){ $log->message("Looks like \`${pkg}' is a package bundle"); $is_bundle=1; my @bundlepkgs = split(/\s+/, $description->{"Contains"}); $pkgs = join(" ", @bundlepkgs); } if($WINDOWS) { my $filename = "${pkgname}_" . $description->{"Version"}; $log->message("building \`$filename.zip'"); system("zip -r9X $startdir/$filename.zip $pkgs"); chdir($startdir); } else { my $filename = "${pkgname}_" . $description->{"Version"} . "_R_${R_platform}.tar"; $log->message("building \`$filename.gz'"); system("tar chf $startdir/$filename $pkgs"); chdir($startdir); system("gzip -9f $filename"); } rmtree($libdir); } else{ if($description->{"Contains"}){ $log->message("Looks like \`${pkg}' is a package bundle"); $is_bundle=1; my @bundlepkgs = split(/\s+/, $description->{"Contains"}); my $ppkg=""; foreach $ppkg (@bundlepkgs){ $log->message("preparing \`$ppkg' in bundle \`$pkg':"); $log->setstars("**"); chdir($startdir); prepare_pkg("$pkg/$ppkg", $is_bundle, $description, $log); $log->setstars("*"); } } else{ $is_bundle=0; chdir($startdir); $log->message("preparing \`$pkg':"); prepare_pkg("$pkg", $is_bundle, $description, $log); } chdir($startdir); $log->message("removing junk files"); find(\&deleteJunkFiles, $pkg); $exclude = "$tmpdir/Rbuild.$$"; open exclude, "> $exclude" || die "Cannot write to \`$exclude'\n"; binmode exclude if $WINDOWS; @excludepatterns = ("^.Rbuildignore\$", "\~\$", "\.swp\$"); if(-f "$pkg/.Rbuildignore") { open(RBUILDIGNORE, "$pkg/.Rbuildignore"); while() { chop; push(@excludepatterns, $_); } close(RBUILDIGNORE); } chdir("$pkg/.."); find(\&findExcludeFiles, "$pkgname"); close exclude; my $filename = "${pkgname}_" . $description->{"Version"} . ".tar"; $log->message("building \`$filename.gz'"); my $filepath = "$startdir/$filename"; if($WINDOWS) { ## workaround for paths in Cygwin tar $filepath =~ s+^([A-Za-x]):+//\1+; } system("tar chXf $exclude $filepath $pkgname"); chdir($startdir); system("gzip -9f $filename"); unlink($exclude); } $log->close(); print("\n"); } sub deleteJunkFiles { unlink($_) if /^(\.RData|\.Rhistory)$/; if(/^DESCRIPTION$/){ unlink($_) if (-f "DESCRIPTION.in"); } } sub findExcludeFiles { print exclude "$File::Find::name\n" if(-d $_ && /^check$/); print exclude "$File::Find::name\n" if(-d $_ && /^chm$/); print exclude "$File::Find::name\n" if(-d $_ && /[Oo]ld$/); print exclude "$File::Find::name\n" if /^GNUMakefile$/; print exclude "$File::Find::name\n" if /^CVS$/; my $filename = $File::Find::name; $filename =~ s/^[^\/]*\///; foreach $p (@excludepatterns) { print exclude "$File::Find::name\n" if($filename =~ /$p/); } } #********************************************************** sub prepare_pkg { my ($pkg, $in_bundle, $description, $log) = @_; chdir($pkg); my $pkgdir = cwd(); my $pkgname = basename($pkg); if(-d "src"){ chdir("src"); $log->message("cleaning src"); if($WINDOWS) { if(-r "Makefile.win") { system("$make -f Makefile.win clean"); } else { my $file; foreach $file (<*.o $pkgname.a $pkgname.dll $pkgname.def>){ unlink($file); } } } else{ my $file; foreach $file (<*.o *s[lo]>){ unlink($file); } } } chdir($pkgdir); if(!$WINDOWS && -x "./cleanup"){ $log->message("running cleanup"); system("./cleanup"); } updateIndex("INDEX", "man", 0, $log); updateIndex("data/00Index", "man", 1, $log) if(-d "data"); 1; } #********************************************************** sub updateIndex { my ($oldindex, $Rdfiles, $dataset, $log) = @_; my $newindex = ".Rbuildindex.$$"; $log->checking("whether \`$oldindex' is up-to-date"); my $dataopt = "-d" if $dataset; system("${R_CMD} Rdindex $dataopt ${Rdfiles} > ${newindex}"); if(-r $oldindex){ if(compare($oldindex, $newindex) != 0){ $log->result("NO"); if($opt_force){ $log->message("overwriting \`${oldindex}' as " . "\`--force' was given"); unlink $oldindex ; rename($newindex, $oldindex); } else{ $log->message("use \`--force' to overwrite the existing \`${oldindex}'"); unlink $newindex; } } else{ $log->result("OK"); unlink $newindex; } } else{ $log->result("NO"); $log->message("creating new $oldindex"); unlink $oldindex ; rename($newindex, $oldindex); } 1; } #********************************************************** sub usage { print STDERR <. END exit 0; }