can download plant phenotype data in the same way as plot phenotype data
[sgn.git] / lib / SGN / Build.pm
blob52d5b93c08053ceaa39447292d62b800bca79e68
1 package SGN::Build;
2 use strict;
3 use warnings;
5 use version;
7 my $HAVE_PARSE_DEB_CONTROL;
9 BEGIN {
10 eval { require Parse::Deb::Control };
11 if( $@ ) {
12 warn "WARNING: Failed to load Parse::Deb::Control, and it is needed to check R dependencies:\n$@\n"
14 $HAVE_PARSE_DEB_CONTROL = !$@;
17 use Module::Build;
18 use base 'Module::Build';
20 my $HAVE_CAPTURE;
21 BEGIN {
22 eval { require Capture::Tiny };
23 $HAVE_CAPTURE = !$@;
26 # we should probably convert this to autodie at some point
28 # build action just runs make on programs
29 sub ACTION_build {
30 my $self = shift;
31 $self->SUPER::ACTION_build(@_);
32 system "make -C programs";
33 if($?) {
34 _handle_errors($?);
35 die "make -C programs failed\!n";
38 unless( $ENV{SGN_SHIPWRIGHT_BUILDING} ) {
39 $self->check_R
40 or die "R dependency check failed, aborting.\n";
44 # override install to just copy the whole dir into the install_base
45 sub ACTION_install {
46 my $self = shift;
48 # installation is just copying the entire dist into
49 # install_base/sgn
50 require File::Spec;
51 my $tgt_dir = File::Spec->catdir($self->install_base,'sgn');
52 system 'cp', '-rl', '.', $tgt_dir;
53 if($?) {
54 _handle_errors($?);
55 die "SGN site copy ( cp -rl . $tgt_dir ) failed!\n";
59 sub ACTION_clean {
60 shift->SUPER::ACTION_clean(@_);
61 system "make -C programs clean";
62 if($?) {
63 _handle_errors($?);
64 die "make -C programs clean failed!\n";
68 sub ACTION_installdeps {
69 my $self = shift;
71 $self->_R_installdeps;
73 $self->SUPER::ACTION_installdeps( @_ );
76 sub create_build_script {
77 my $self = shift;
79 $self->check_R
80 or warn $self->{R}{check_output};
82 return $self->SUPER::create_build_script(@_);
85 sub check_R {
86 my ( $self, @args ) = @_;
87 if( $HAVE_CAPTURE ) {
88 my $ret;
89 my $out = Capture::Tiny::capture_merged {
90 $ret = $self->_run_R_check( @args );
93 $self->{R}{check_output} = $out;
94 if( !$ret and my ($missing) = $out =~ /required but not available:\s+(\S(?:[^\n]+\n)+)\n/si ) {
95 $self->{R}{missing_packages} = [ split /\s+/, $missing ];
98 return $ret;
99 } else {
100 return $self->_run_R_check( @args );
104 sub _R_installdeps {
105 my ( $self ) = @_;
107 if( $self->check_R ) {
108 print "All R prerequisites satisfied\n";
109 return;
112 my @missing_packages = @{ $self->{R}{missing_packages} || [] };
113 unless( @missing_packages ) {
114 print "No missing R packages detected, cannot installdeps for R.\n";
115 return;
118 my $package_vec = 'c('.join( ',', map qq|"$_"|, @missing_packages ).')';
119 my $cran_mirror = $ENV{CRAN_MIRROR} || "http://lib.stat.cmu.edu/R/CRAN";
121 my $tf = File::Temp->new;
122 $tf->print( <<EOR );
123 userdir <- unlist(strsplit(Sys.getenv("R_LIBS_USER"), .Platform\$path.sep))[1L]
124 if (!file.exists(userdir) && !dir.create(userdir, recursive = TRUE, showWarnings = TRUE))
125 stop("unable to create ", sQuote(userdir))
126 .libPaths(c(userdir, .libPaths()))
127 install.packages( $package_vec, contriburl = contrib.url("$cran_mirror") )
129 $tf->close;
131 # use system so the user will be able to use the R graphical
132 # mirror chooser, and other things
133 system 'R', '--slave', -f => "$tf", '--no-save', '--no-restore';
134 if( $? ) {
135 _handle_errors($?);
136 warn "Failed to automatically install R dependencies\n";
137 } elsif( $self->check_R ) {
138 print "Successfully installed R dependencies.\n";
142 sub _handle_errors {
143 my ($exit_code) = @_;
144 if ($exit_code == -1) {
145 print "Error: failed to execute: $!\n";
146 } elsif ($exit_code & 127) {
147 warn sprintf("Error: child died with signal %d, %s coredump\n",
148 ($exit_code & 127), ($exit_code & 128) ? 'with' : 'without');
149 } else {
150 warn sprintf("Error: child exited with value %d\n",$exit_code >> 8);
154 sub _run_R_check {
155 my $self = shift;
157 print "\nChecking R prerequisites...\n";
159 # check the R version ourself, since R CMD check apparently does
160 # not do it.
161 $self->_check_R_version
162 or return 0;
164 my $no_manual = $self->_R_version_current ge version->new('3.2.0') ? '--no-manual' : '';
166 my $ret = system "R CMD check $no_manual --no-codoc --no-vignettes -o _build R_files";
167 if ( $ret || $? ) {
168 _handle_errors($?);
169 warn "\nR PREREQUISITE CHECK FAILED.\n\n";
170 return 0;
171 } else {
172 print "R prerequisites OK.\n\n";
173 return 1;
177 sub _check_R_version {
178 my $self = shift;
181 unless ($HAVE_PARSE_DEB_CONTROL) {
182 warn "Parse::Deb::Control not present, skipping R configuration";
183 return 0;
185 my ( $cmp, $v ) = $self->_R_version_required;
187 if( eval '$self->_R_version_current'." $cmp version->parse('$v')" ) {
188 return 1;
189 } else {
190 warn "R VERSION CHECK FAILED, we have ".$self->_R_version_current.", but we require $cmp $v.\n";
191 warn "To install R : sudo aptitude install r-base-core\n\n";
192 return 0;
196 # parse and return the R DESCRIPTION file
197 sub _R_desc {
198 return Parse::Deb::Control->new([qw[ R_files DESCRIPTION ]]);
201 # parse and return the version of R we require as string list like
202 # ('>=','2.10.0')
203 sub _R_version_required {
204 my $self = shift;
205 my @k = $self->_R_desc->get_keys('Depends')
206 or return ( '>=', 0 );
207 my ($version) = ${$k[0]->{value}} =~ / \b R \s* \( ([^\)]+) /x
208 or return ( '>=', 0 );
210 my @v = split /\s+/, $version;
211 unshift @v, '==' unless @v > 1;
213 return @v;
216 # parse and return the current R version as a version object
217 sub _R_version_current {
218 my $r = `R --version`;
219 return 0 unless $r;
221 $r =~ /R version ([\d\.]+)/;
223 return version->new($1);