package GBrowseInstall;
use base 'Module::Build';
use strict;
use warnings;
use ExtUtils::CBuilder;
use ExtUtils::MakeMaker 'prompt';
use Cwd;
use File::Basename 'dirname','basename';
use File::Path 'rmtree','mkpath';
use File::Temp 'tempdir';
use File::Spec;
use IO::File;
use IO::Dir;
use File::Compare 'compare';
use File::Copy 'copy','cp';
use GBrowseGuessDirectories;
use Carp 'cluck';
use overload '""' => 'asString',
fallback => 1;
use constant REGISTRATION_SERVER => 'http://modencode.oicr.on.ca/cgi-bin/gbrowse_registration';
my @OK_PROPS = (conf => 'Directory for GBrowse\'s config and support files?',
htdocs => 'Directory for GBrowse\'s static images & HTML files?',
tmp => 'Directory for GBrowse\'s temporary data',
persistent => 'Directory for GBrowse\'s sessions, uploaded tracks and other persistent data',
databases => 'Directory for GBrowse\'s example databases',
cgibin => 'Directory for GBrowse\'s CGI script executables?',
portdemo => 'Internet port to run demo web site on (for demo)?',
apachemodules => 'Apache loadable module directory (for demo)?',
wwwuser => 'User account under which Apache daemon runs?',
installconf => 'Automatically update Apache config files to run GBrowse?',
installetc => 'Automatically update system config files to run gbrowse-slave?',
);
my %OK_PROPS = @OK_PROPS;
# TO FIX: this contains much of the same code as in the non-demo build
# and should be refactored.
sub ACTION_demo {
my $self = shift;
$self->depends_on('config_data');
$self->depends_on('build');
my $dir = tempdir(
'GBrowse_demo_XXXX',
TMPDIR=>1,
CLEANUP=>0,
);
my $port = $self->config_data('portdemo')
|| GBrowseGuessDirectories->portdemo();
my $modules = $self->config_data('apachemodules')
|| GBrowseGuessDirectories->apachemodules;
my $db = $self->config_data('databases')
|| GBrowseGuessDirectories->databases;
my $cgiurl = $self->cgiurl;
my $persistent = $self->config_data('persistent');
mkdir "$dir/conf";
mkdir "$dir/htdocs";
mkdir "$dir/logs";
mkdir "$dir/locks";
mkdir "$dir/tmp";
# make copies of htdocs and conf
open my $saveout,">&STDOUT";
open STDOUT,">/dev/null";
my $f = IO::File->new('MANIFEST');
while (<$f>) {
chomp;
if (m!^(conf|htdocs)!) {
$self->copy_if_modified($_ => $dir);
} elsif (m!cgi-bin!) {
$self->copy_if_modified(from => $_,to_dir => "$dir/cgi-bin/gb2",flatten=>1);
} elsif (m!^sample_data!) {
chdir $self->base_dir();
my ($subdir) = m!^sample_data/([^/]+)/!;
$self->copy_if_modified(from => $_,
to_dir => "$dir/htdocs/databases/$subdir",
flatten => 1,
);
}
}
close $f;
chdir $self->base_dir;
open STDOUT,"<&",$saveout;
# fix GBrowse.conf to point to correct directories
for my $f ("$dir/conf/GBrowse.conf",
"$dir/conf/yeast_simple.conf",
"$dir/conf/yeast_chr1+2.conf",
"$dir/conf/pop_demo.conf",
"$dir/conf/yeast_renderfarm.conf",
"$dir/htdocs/index.html") {
my $in = IO::File->new($f) or die "$dir/conf/$f: $!";
my $out = IO::File->new("$f.new",'>') or die $!;
while (<$in>) {
s!\$CONF!$dir/conf!g;
s!\$HTDOCS!$dir/htdocs!g;
s!\$DATABASES!$dir/htdocs/databases!g;
s!\$PERSISTENT!$dir/$persistent!g;
s!\$TMP!$dir/tmp!g;
s/\$CGIURL/$cgiurl/g;
s!\$VERSION!$self->dist_version!eg;
s/\$CAN_USER_ACCOUNTS_OPENID/$self->has_openid/eg;
s/\$CAN_USER_ACCOUNTS_REG/$self->has_smtp/eg;
s/\$CAN_USER_ACCOUNTS/$self->has_mysql_or_sqlite/eg;
s/\$USER_ACCOUNT_DB/$self->guess_user_account_db/eg;
s/\$SMTP_GATEWAY/$self->guess_smtp_gateway/eg;
s!^url_base\s*=.+!url_base = /!g;
s!^user_accounts[^=]+=.*!user_accounts = 0!;
$out->print($_);
}
close $out;
rename "$f.new",$f;
}
my $conf_data = $self->httpd_conf($dir,$port);
my $conf = IO::File->new("$dir/conf/httpd.conf",'>')
or die "$dir/conf/httpd.conf: $!";
$conf->print($conf_data);
$conf->close;
$conf_data = $self->gbrowse_demo_conf($port,$dir);
$conf = IO::File->new("$dir/conf/apache_gbrowse.conf",'>')
or die "$dir/conf/apache_gbrowse.conf: $!";
$conf->print($conf_data);
$conf->close;
$conf_data = $self->mime_conf();
my $mime = IO::File->new("$dir/conf/mime.types",'>')
or die "$dir/conf/mime.types: $!";
$mime->print($conf_data);
$mime->close;
my $apache = GBrowseGuessDirectories->apache
or die "Could not find apache executable on this system. Can't run demo";
system "$apache -k start -f $dir/conf/httpd.conf";
sleep 3;
if (-e "$dir/logs/apache2.pid") {
print STDERR "Demo config and log files have been written to $dir\n";
print STDERR "Demo is now running on http://localhost:$port\n";
print STDERR "Run \"./Build demostop\" to stop it.\n";
$self->config_data(demodir=>$dir);
} else {
print STDERR "Apache failed to start. Perhaps the demo is already running?\n";
if (-e "$dir/logs/error.log") {
print STDERR "==Apache Error Log==\n";
my $f = IO::File->new("$dir/logs/error.log");
print STDERR while <$f>;
}
rmtree([$dir]);
}
}
sub ACTION_demostop {
my $self = shift;
my $dir = $self->config_data('demodir');
my $home = $self->base_dir();
unless ($dir && -e $dir) {
print STDERR "Demo doesn't seem to be running.\n";
return;
}
my $apache = GBrowseGuessDirectories->apache
or die "Could not find apache executable on this system. Can't stop demo";
system "$apache -k stop -f $dir/conf/httpd.conf";
rmtree([$dir,"$home/htdocs/tmp"]);
$self->config_data('demodir'=>undef);
print STDERR "Demo stopped.\n";
}
sub ACTION_clean {
my $self = shift;
$self->SUPER::ACTION_clean;
unlink 'INSTALL.SKIP';
}
sub ACTION_realclean {
my $self = shift;
$self->SUPER::ACTION_realclean;
foreach ('CAlign.xs','CAlign.pm') {
unlink "./lib/Bio/Graphics/Browser/$_";
}
}
sub ACTION_build {
my $self = shift;
$self->depends_on('config');
$self->depends_on('register') unless $self->registration_done;
$self->SUPER::ACTION_build;
mkdir './htdocs/tmp';
chmod 0777,'./htdocs/tmp';
}
sub ACTION_reconfig {
my $self = shift;
$self->config_done(0);
unless (Module::Build->y_n("Reuse previous configuration as defaults?",'y')) {
for (keys %{$self->private_props}) {
$self->config_data($_=>undef);
}
}
$self->depends_on('config_data');
warn "\n**Paths reconfigured. Running \"Build clean\".\n";
$self->ACTION_clean;
}
sub ACTION_test {
my $self = shift;
$self->depends_on('config_data');
$self->SUPER::ACTION_test;
}
sub ACTION_distclean {
my $self = shift;
$self->SUPER::ACTION_distclean;
rmtree(['debian/libgbrowse-perl']);
}
sub ACTION_config {
my $self = shift;
local $^W = 0;
my $prefix = $self->install_base || $self->prefix || '';
GBrowseGuessDirectories->prefix($prefix);
# $self->depends_on('build');
return if $self->config_done;
print STDERR "\n**Beginning interactive configuration**\n";
my $props = $self->private_props;
my %opts = map {
$_=>$self->config_data($_)
} keys %$props;
my @keys = @OK_PROPS;
while (@keys) {
my $key = shift @keys;
my $val = shift @keys; # not used
# next if $self->config_data($key);
my $conf_dir = $props->{$key} =~ /directory/i;
$opts{$key} = prompt($props->{$key},
$opts{$key} ||
($conf_dir
? File::Spec->canonpath(
File::Spec->catfile(GBrowseGuessDirectories->$key($opts{apache})))
: GBrowseGuessDirectories->$key($opts{apache})));
if ($conf_dir) {
my ($volume,$dir) = File::Spec->splitdir($opts{$key});
my $top_level = File::Spec->catfile($volume,$dir);
unless (-d $top_level) {
next if Module::Build->y_n("The directory $top_level does not exist. Use anyway?",'n');
redo;
}
}
}
for my $key (keys %opts) {
$self->config_data($key=>$opts{$key});
}
$self->config_done(1);
print STDERR "\n**Interactive configuration done. Run './Build reconfig' to reconfigure**\n";
}
sub ACTION_register {
my $self = shift;
return unless -t STDIN;
print STDERR "\n**Registration**\nGBrowse2 registration is optional, but will help us maintain funding for this project.\n";
if (Module::Build->y_n("Do you wish to register your installation?",'y')) {
print STDERR "All values are optional, but appreciated.\n";
my $user = prompt('Your name:');
my $email = prompt('Your email address:');
my $org = prompt('Your organization:');
my $organism = prompt('Organisms you will be using GBrowse for (one line):');
my $site = prompt('If GBrowse will be public, the URL of your web site:');
my $result = eval {
eval "use HTTP::Request::Common";
eval "use LWP::UserAgent";
my $ua = LWP::UserAgent->new;
my $response = $ua->request(POST(REGISTRATION_SERVER,
[user=>$user,email=>$email,
org=>$org,organism=>$organism,
site=>$site]
));
die $response->status_line unless $response->is_success;
my $content = $response->decoded_content;
$content eq 'ok';
};
if ($@) {
print STDERR "An error occurred during registration: $@\n";
print STDERR "If you are able to fix the error, you can register later ";
print STDERR "using \"./Build register\"\n";
} else {
print STDERR $result ? "Thank you. Your registration was sent successfully.\n"
: "An error occurred during registration. Thanks anyway.\n";
}
} else {
print STDERR "If you wish to register at a later time please \"./Build register\"\n";
print STDERR "Press any key to continue\n";
my $h = <STDIN>;
}
$self->registration_done(1);
}
sub ACTION_config_data {
my $self = shift;
$self->depends_on('config');
$self->SUPER::ACTION_config_data;
}
sub ACTION_apache_conf {
my $self = shift;
$self->depends_on('config');
my $docs = basename($self->config_data('htdocs'));
print STDERR <<END;
INSTRUCTIONS: Paste the following into your Apache configuration
file. You may wish to save it separately and include it using the
Apache "Include /path/to/file" directive. Then restart Apache and
point your browser to http://your.site/$docs/ to start browsing the
sample genomes.
>>>>>> cut here <<<<<
END
;
print $self->apache_conf;
}
sub apache_conf {
my $self = shift;
my $dir = $self->config_data('htdocs');
my $conf = $self->config_data('conf');
my $cgibin = $self->config_data('cgibin');
my $tmp = $self->config_data('tmp');
my $databases = $self->config_data('databases');
my $cgiroot = basename($cgibin);
my $perl5lib= $self->added_to_INC;
my $inc = $perl5lib ? "SetEnv PERL5LIB \"$perl5lib\"" : '';
my $fcgi_inc = $perl5lib ? "-initial-env PERL5LIB=$perl5lib" : '';
my $fcgid_inc= $perl5lib ? "FcgidInitialEnv PERL5LIB $perl5lib" : '';
my $modperl_switches = $perl5lib
? "PerlSwitches ".join ' ',map{"-I$_"} split ':',$perl5lib
: '';
return <<END;
Alias "/gbrowse2/i/" "$tmp/images/"
Alias "/gbrowse2" "$dir"
ScriptAlias "/gb2" "$cgibin"
<Directory "$dir">
AllowOverride Options
Options -Indexes -MultiViews +FollowSymLinks
Order allow,deny
Allow from all
</Directory>
<Directory "$dir/tutorial">
Options +Indexes
</Directory>
<Directory "$tmp/images/">
Order allow,deny
Allow from all
</Directory>
<Directory "$databases">
Order allow,deny
Deny from all
</Directory>
<Directory "$cgibin">
${inc}
Options ExecCGI
SetEnv GBROWSE_CONF "$conf"
</Directory>
<IfModule mod_fcgid.c>
Alias /fgb2 "$cgibin"
<Location /fgb2>
SetHandler fcgid-script
</Location>
FcgidInitialEnv GBROWSE_CONF $conf
# these directives prevent idle/busy timeouts and may need to be
# adjusted up or down
FcgidMinProcessesPerClass 6
FcgidIOTimeout 600
FcgidBusyTimeout 600
$fcgid_inc
</IfModule>
<IfModule mod_fastcgi.c>
Alias /fgb2 "$cgibin"
<Location /fgb2>
SetHandler fastcgi-script
</Location>
# Note: you may need to increase -idle-timeout if file uploads are timing out and returning server
# errors.
FastCgiConfig -idle-timeout 600 -maxClassProcesses 20 $fcgi_inc -initial-env GBROWSE_CONF=$conf
</IfModule>
# Use of mod_perl is no longer supported. Use at your own risk.
<IfModule mod_perl.c>
Alias /mgb2 "$cgibin"
$modperl_switches
<Location /mgb2>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
</Location>
</IfModule>
END
}
sub ACTION_install {
my $self = shift;
my $prefix = $self->install_base || $self->prefix || '';
GBrowseGuessDirectories->prefix($prefix);
$self->depends_on('config_data');
$self->install_path->{conf}
||= $self->config_data('conf') || GBrowseGuessDirectories->conf;
$self->install_path->{htdocs}
||= $self->config_data('htdocs')
|| GBrowseGuessDirectories->htdocs;
$self->install_path->{'cgi-bin'}
||= $self->config_data('cgibin')
|| GBrowseGuessDirectories->cgibin;
$self->install_path->{'etc'}
||= GBrowseGuessDirectories->etc;
$self->install_path->{'databases'}
||= $self->config_data('databases')
|| GBrowseGuessDirectories->databases;
$self->install_path->{'persistent'}
||= $self->config_data('persistent')
|| GBrowseGuessDirectories->persistent;
$self->SUPER::ACTION_install();
my $user = $self->config_data('wwwuser') || GBrowseGuessDirectories->wwwuser;
# fix some directories so that www user can write into them
my $tmp = $self->config_data('tmp') || GBrowseGuessDirectories->tmp;
mkpath($tmp);
my ($uid,$gid) = (getpwnam($user))[2,3];
# taint check issues
$uid =~ /^(\d+)$/;
$uid = $1;
$gid =~ /^(\d+)$/;
$gid = $1;
unless (chown $uid,$gid,$tmp) {
$self->ownership_warning($tmp,$user);
}
my $htdocs_i = File::Spec->catfile($self->install_path->{htdocs},'i');
my $images = File::Spec->catfile($tmp,'images');
my $htdocs = $self->install_path->{htdocs};
chown $uid,-1,$htdocs;
{
local $> = $uid;
symlink($images,$htdocs_i); # so symlinkifowner match works!
}
chown $>,-1,$self->install_path->{htdocs};
my $persistent = $self->install_path->{'persistent'};
my $sessions = File::Spec->catfile($persistent,'sessions');
my $userdata = File::Spec->catfile($persistent,'userdata');
mkpath([$sessions,$userdata],0711);
my $databases = $self->install_path->{'databases'};
unless (chown $uid,$gid,glob(File::Spec->catfile($databases,'').'*')) {
$self->ownership_warning($databases,$user);
}
chmod 0755,File::Spec->catfile($self->install_path->{'etc'},'init.d','gbrowse-slave');
$self->fix_selinux;
my $base = basename($self->install_path->{htdocs});
# Configure the databases, if needed.
print STDERR "Updating user account database...\n";
my $metadb_script = File::Spec->catfile("bin", "gbrowse_metadb_config.pl");
my $perl = $self->perl;
my @inc = map{"-I$_"} split ':',$self->added_to_INC;
system $perl,@inc,$metadb_script;
system 'sudo','chown','-R',"$uid.$gid",$sessions,$userdata;
if (Module::Build->y_n(
"It is recommended that you restart Apache. Shall I try this for you?",'y'
)) {
system "sudo /etc/init.d/apache2 restart";
}
print STDERR "\n***INSTALLATION COMPLETE***\n";
print STDERR "Load http://localhost/$base for demo and documentation.\n";
print STDERR "Visit the http://gmod.org for more information on setting up databases for users and custom tracks.\n";
}
sub ACTION_install_slave {
my $self = shift;
my $prefix = $self->install_base || $self->prefix ||'';
GBrowseGuessDirectories->prefix($prefix);
$self->install_path->{'etc'} ||= GBrowseGuessDirectories->etc;
$self->SUPER::ACTION_install();
}
sub ACTION_debian {
my $self = shift;
system "debuild";
}
sub fix_selinux {
my $self = shift;
return unless -e '/proc/filesystems';
my $f = IO::File->new('/proc/filesystems') or return;
return unless grep /selinux/i,<$f>;
my $enabled = IO::File->new('/selinux/enforce') or return;
return unless grep /1/,<$enabled>;
print STDERR "\n*** SELinux detected -- fixing permissions ***\n";
my $htdocs = $self->config_data('htdocs');
my $conf = $self->config_data('conf');
my $tmp = $self->config_data('tmp');
my $db = $self->config_data('databases');
system "/usr/bin/chcon -R -t httpd_sys_content_t $conf";
system "/usr/bin/chcon -R -t httpd_sys_content_t $htdocs";
system "/usr/bin/chcon -R -t httpd_sys_content_rw_t $tmp";
system "/usr/bin/chcon -R -t httpd_sys_content_rw_t $db";
}
sub process_conf_files {
my $self = shift;
my $f = IO::File->new('MANIFEST');
my $prefix = $self->install_base || $self->prefix || '';
GBrowseGuessDirectories->prefix($prefix);
my $install_path = $self->config_data('conf') || GBrowseGuessDirectories->conf;
while (<$f>) {
next unless m!^conf/!;
chomp;
my $base = $_;
my $copied = $self->copy_if_modified($_=>'blib');
if ($copied || !$self->up_to_date('_build/config_data',"blib/$_")) {
$self->substitute_in_place("blib/$_");
$self->check_installed($install_path,$base);
}
}
}
sub check_installed {
my $self = shift;
my ($install_path,$blib_file) = @_;
my $skip = $self->{skip} ||= IO::File->new('>>INSTALL.SKIP') or die "INSTALL.SKIP: $!";
(my $base = $blib_file) =~ s!^[^/]+/!!;
my $staged = File::Spec->catfile('./blib',$blib_file);
my $installed = File::Spec->catfile($install_path,$base);
if (-e $installed && (compare($staged,$installed) != 0)) {
my ($confirmed,$keep);
if ($ENV{AUTOMATED_TESTING}) {
$confirmed++;
$keep++;
}
while (!$confirmed) {
print STDERR "$installed has changed. Should \"Build install\" [R]eplace with new version or [K]eep currently installed version [K]? ";
my $line = <>;
chomp($line);
$line ||= '';
if ($line =~ /^[Kk]/) {
$keep++;
$confirmed++;
} elsif ($line =~ /^[Rr]/) {
$confirmed++;
} elsif ($line =~ /^$/) {
$keep++;
$confirmed++;
}
}
if ($keep) {
print STDERR "\"Build install\" will keep original $installed. New version can be found in ${installed}.new\n\n";
cp($staged,"${staged}.new");
print $skip '^',"blib/",quotemeta($blib_file),'$',"\n";
} else {
print STDERR "\"Build install\" will replace original $installed. Original version can be found in ${installed}.orig\n\n";
cp($installed,"${staged}.orig");
}
}
}
sub process_htdocs_files {
my $self = shift;
my $f = IO::File->new('MANIFEST');
my $install_path = $self->install_path->{'htdocs'} || GBrowseGuessDirectories->htdocs;
my %doneit;
while (<$f>) {
next unless m!^htdocs/!;
chomp;
my $base = $_;
my $copied = $self->copy_if_modified($base=>'blib');
if ($copied or !$self->up_to_date('_build/config_data',"blib/$base")) {
$self->substitute_in_place("blib/$base");
$self->check_installed($install_path,$base) if $copied;
}
}
}
sub process_cgibin_files {
my $self = shift;
my $f = IO::File->new('MANIFEST');
while (<$f>) {
next unless m!^cgi-bin/!;
chomp;
my $copied = $self->copy_if_modified($_=>'blib');
my $path = File::Spec->catfile('blib',$_);
if ($copied) {
$self->fix_shebang_line($path);
chmod 0755,$path;
}
}
}
sub process_etc_files {
my $self = shift;
my $prefix = $self->install_base || $self->prefix || '';
GBrowseGuessDirectories->prefix($prefix);
my $install_path = $self->install_path->{'etc'} || GBrowseGuessDirectories->etc;
if ($self->config_data('installetc') =~ /^[yY]/) {
my $f = IO::File->new('MANIFEST');
while (<$f>) {
next unless m!^etc/!;
chomp;
my $base = $_;
my $copied = $self->copy_if_modified($_=>'blib');
if ($copied or !$self->up_to_date('_build/config_data',"blib/$_")) {
$self->substitute_in_place("blib/$_");
$self->check_installed($install_path,$base);
}
}
}
# generate the apache config data
my $includes = GBrowseGuessDirectories->apache_includes || '';
# the following workaround checks for perl.conf (which must load before gbrowse.conf on modperl envs)
# and renames the file so that it is loaded after perl.conf
my $file = -e "${includes}/perl.conf"
? 'z_gbrowse2.conf'
: 'gbrowse2.conf';
my $target = "blib${includes}/$file";
if ($includes && !$self->up_to_date('_build/config_data',$target)) {
if ($self->config_data('installconf') =~ /^[yY]/ && !-e "${includes}/$file") {
warn "Creating include file for Apache config: $target\n";
my $dir = dirname($target);
mkpath([$dir]);
if (my $f = IO::File->new("blib${includes}/$file",'>')) {
$f->print($self->apache_conf);
$f->close;
}
} else {
print STDERR
-e "${includes}/$file"
? "${includes}/$file is already installed. "
: "Automatic Apache config disabled. ";
print STDERR "Please run ./Build apache_conf to see this file's recommended contents.\n";
}
}
if (!$self->config_data('installetc') =~ /^[yY]/) {
warn "Not configuring your system to run gbrowse-slave automatically. Please reconfigure with this option enabled if you wish to do this.";
}
}
sub process_database_files {
my $self = shift;
my $f = IO::File->new('MANIFEST');
while (<$f>) {
next unless m!^sample_data/!;
chomp;
my $dest = $_; $dest =~ s|^sample_data/||;
$self->copy_if_modified(from => $_,
to => "blib/databases/$dest",
);
}
}
sub substitute_in_place {
my $self = shift;
my $path = shift;
return if $path =~ /\.\w+$/ && $path !~ /\.(html|txt|conf)$/;
my $in = IO::File->new($path) or return;
my $out = IO::File->new("$path.$$",'>') or return;
print STDERR "Performing variable substitutions in $path\n";
my $htdocs = $self->config_data('htdocs');
my $conf = $self->config_data('conf');
my $cgibin = $self->config_data('cgibin');
my $persistent = $self->config_data('persistent');
my $databases = $self->config_data('databases');
my $tmp = $self->config_data('tmp');
my $wwwuser = $self->config_data('wwwuser');
my $perl5lib = $self->perl5lib || '';
my $installscript = $self->install_destination('script');
my $etc = $self->install_path->{'etc'} ||= GBrowseGuessDirectories->etc;
my $cgiurl = $self->cgiurl;
$persistent ||= $databases;
while (<$in>) {
s/\$INSTALLSCRIPT/$installscript/g;
s/\$ETC/$etc/g;
s/\$PERL5LIB/$perl5lib/g;
s/\$HTDOCS/$htdocs/g;
s/\$CONF/$conf/g;
s/\$CGIBIN/$cgibin/g;
s/\$CGIURL/$cgiurl/g;
s/\$WWWUSER/$wwwuser/g;
s/\$DATABASES/$databases/g;
s/\$PERSISTENT/$persistent/g;
s/\$VERSION/$self->dist_version/eg;
s/\$CAN_USER_ACCOUNTS_OPENID/$self->has_openid/eg;
s/\$CAN_USER_ACCOUNTS_REG/$self->has_smtp/eg;
s/\$CAN_USER_ACCOUNTS/$self->has_mysql_or_sqlite/eg;
s/\$USER_ACCOUNT_DB/$self->guess_user_account_db/eg;
s/\$SMTP_GATEWAY/$self->guess_smtp_gateway/eg;
s/\$TMP/$tmp/g;
$out->print($_);
}
$in->close;
$out->close;
rename("$path.$$",$path);
}
sub has_mysql_or_sqlite {
my $self = shift;
return eval "require DBD::mysql; 1" || eval "require DBD::SQLite; 1" || 0;
}
sub has_smtp {
my $self = shift;
return eval "require Net::SMTP; 1" || 0;
}
sub has_openid {
my $self = shift;
return eval "require Net::OpenID::Consumer; require LWP::UserAgent; 1" || 0;
}
sub guess_user_account_db {
my $self = shift;
if (eval "require DBD::SQLite; 1") {
my $databases = $self->config_data('databases');
return "DBI:SQLite:$databases/users.sqlite";
} elsif (eval "require DBD::mysql; 1") {
return 'DBI:mysql:gbrowse_login;user=gbrowse;password=gbrowse';
} else {
return "no database defined # please correct this";
}
}
sub guess_smtp_gateway {
my $self = shift;
return 'localhost # this assumes that a correctly configured smtp server is running on current machine; change if necessary';
}
sub private_props {
return \%OK_PROPS;
}
sub valid_property {
my $self = shift;
my $prop = shift;
return $OK_PROPS{$prop} || $self->SUPER::valid_property($prop);
}
sub httpd_conf {
my $self = shift;
my ($dir,$port) = @_;
my $modules = $self->config_data('apachemodules')
|| GBrowseGuessDirectories->apachemodules;
my $user = $>;
my ($group) = $) =~ /^(\d+)/;
return <<END;
ServerName "localhost"
ServerRoot "$dir/conf"
LockFile "$dir/locks/accept.lock"
PidFile "$dir/logs/apache2.pid"
ErrorLog "$dir/logs/error.log"
LogFormat "%h %l %u %t \\"%r\\" %>s %b" common
CustomLog "$dir/logs/access.log" common
LogLevel warn
User #$user
Group #$group
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
DefaultType text/plain
HostnameLookups Off
<IfModule so_module>
<IfModule !log_config_module>
LoadModule log_config_module $modules/mod_log_config.so
</IfModule>
<IfModule !cgid_module>
LoadModule cgid_module $modules/mod_cgid.so
ScriptSock "$dir/logs/cgisock"
</IfModule>
<IfModule !authz_host_module>
LoadModule authz_host_module $modules/mod_authz_host.so
</IfModule>
<IfModule !env_module>
LoadModule env_module $modules/mod_env.so
</IfModule>
<IfModule !alias_module>
LoadModule alias_module $modules/mod_alias.so
</IfModule>
<IfModule !dir_module>
LoadModule dir_module $modules/mod_dir.so
</IfModule>
<IfModule !mime_module>
LoadModule mime_module $modules/mod_mime.so
</IfModule>
</IfModule>
TypesConfig "$dir/conf/mime.types"
Listen $port
Include "$dir/conf/apache_gbrowse.conf"
END
}
sub gbrowse_demo_conf {
my $self = shift;
my ($port,$dir) = @_;
my $blib = File::Spec->catfile($self->base_dir(),$self->blib);
my $inc = "$blib/lib:$blib/arch";
my $more = $self->added_to_INC;
$inc .= ":$more" if $more;
return <<END;
NameVirtualHost *:$port
<VirtualHost *:$port>
ServerAdmin webmaster\@localhost
Alias "/i/" "$dir/tmp/images/"
ScriptAlias "/cgi-bin/" "$dir/cgi-bin/"
DocumentRoot $dir/htdocs/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory $dir/htdocs/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
<Directory "$dir/cgi-bin/">
SetEnv PERL5LIB $inc
SetEnv GBROWSE_MASTER GBrowse.conf
SetEnv GBROWSE_CONF $dir/conf
SetEnv GBROWSE_DOCS $dir/htdocs
SetEnv GBROWSE_ROOT /
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
END
}
sub mime_conf {
my $self = shift;
return <<END;
image/gif gif
image/jpeg jpeg jpg jpe
image/png png
image/svg+xml svg svgz
text/css css
text/html html htm shtml
END
}
sub config_done {
my $self = shift;
my $done = $self->config_data('config_done');
$self->config_data(config_done=>shift) if @_;
warn "NOTE: Run ./Build reconfig to change existing configuration.\n" if $done;
return $done;
}
sub registration_done {
my $self = shift;
my $done = $self->config_data('registration_done');
$self->config_data(registration_done=>shift) if @_;
return $done;
}
sub added_to_INC {
my $self = shift;
my @inc = grep {!/install_util/} eval {$self->_added_to_INC}; # not in published API
my $lib_base = $self->install_destination('lib');
my $arch_base = $self->install_destination('arch');
my %standard = map {$_=>1} @INC;
push @inc,$lib_base unless $standard{$lib_base};
push @inc,$arch_base unless $standard{$arch_base};
return @inc ? join(':',@inc) : '';
}
sub perl5lib {
my $self = shift;
return $self->added_to_INC or undef;
}
sub scriptdir {
my $self = shift;
my $id = $self->installdirs;
my $scriptdir = $id eq 'core' ? 'installscript'
:$id eq 'site' ? 'installsitebin'
:$id eq 'vendor' ? 'installvendorbin'
:'installsitebin';
return $Config::Config{$scriptdir};
}
sub ownership_warning {
my $self = shift;
my ($path,$owner) = @_;
warn "*** WARNING: Using sudo to change ownership of $path to '$owner'. You may be prompted for your login password ***\n";
system "sudo chown -R $owner $path";
}
sub cgiurl {
my $self = shift;
my $cgibin = $self->config_data('cgibin');
(my $cgiurl = $cgibin) =~ s!^.+/cgi-bin!/cgi-bin!;
$cgiurl =~ s!^.+/CGI-Executables!/cgi-bin!; #Macs and their crazy paths
return $cgiurl;
}
sub check_prereq {
my $self = shift;
my $result = $self->SUPER::check_prereq(@_);
unless ($result) {
$self->log_warn(<<END);
* Do not worry if some "recommended" prerequisites are missing. You can install *
* them later if you need the features they provide. Do not proceed with the *
* install if any of "REQUIRED" prerequisites are missing. *
* *
* The optional Safe::World module does not currently run on Perl 5.10 or *
* higher, and so cannot be installed. *
END
}
return $result;
}
sub asString { return 'GBrowse installer' }
1;
__END__
=head1 ACTIONS
=over 4
=item config
Interactively configure the locations in which GBrowse's scripts,
configuration files, and static image/support files will be installed.
One or more of the config options can be set on the command
line when first running perl Build.PL:
perl Build.PL --conf=/etc/gbrowse2 \ # config files
--htdocs=/var/www/gbrowse2 \ # static files
--cgibin=/usr/lib/cgi-bin/gb2 \ # CGI executables
--wwwuser=www-data \ # apache user
--tmp=/var/tmp/gbrowse2 \ # temporary data
--portdemo=8000 \ # demo web site port
--apachemodules=/usr/lib/apache2/modules # apache loadable modules
=item reconfig
Interactively edit configuration locations. See "./Build help config".
=item demo
Try to start an apache/gbrowse instance running in demo mode on the
port specified during "./Build config". This allows you to try GBrowse
without installing it.
=item stopdemo
Stop the demo instance.
=item apache_conf
Generate a fragment of the Apache configuration file needed to run
GBrowse.
=item debian
Build Debian source & binary packages.
=back