# -*- Mode: perl; indent-tabs-mode: nil -*- # # The contents of this file are subject to the Mozilla Public # License Version 1.1 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or # implied. See the License for the specific language governing # rights and limitations under the License. # # The Initial Developer of the Original Code is Everything Solved. # Portions created by Everything Solved are Copyright (C) 2006 # Everything Solved. All Rights Reserved. # # The Original Code is the Bugzilla Bug Tracking System. # # Contributor(s): Max Kanat-Alexander package Bugzilla::Install::Localconfig; # NOTE: This package may "use" any modules that it likes. However, # all functions in this package should assume that: # # * The data/ directory does not exist. # * Templates are not available. # * Files do not have the correct permissions # * The database is not up to date use strict; use Bugzilla::Constants; use Data::Dumper; use IO::File; use Safe; use base qw(Exporter); our @EXPORT_OK = qw( read_localconfig update_localconfig ); use constant LOCALCONFIG_VARS => ( { name => 'create_htaccess', default => 1, desc => < block # in the httpd.conf file that has 'AllowOverride Limit' in it. If it has # 'AllowOverride All' or other options with Limit, that's fine. # (Older Apache installations may use an access.conf file to store these # blocks.) # If this is set to 1, Bugzilla will create these files if they don't exist. # If this is set to 0, Bugzilla will not create these files. EOT }, { name => 'webservergroup', default => ON_WINDOWS ? '' : 'apache', desc => q{# This is the group your web server runs as. # If you have a Windows box, ignore this setting. # If you do not have access to the group your web server runs under, # set this to "". If you do set this to "", then your Bugzilla installation # will be _VERY_ insecure, because some files will be world readable/writable, # and so anyone who can get local access to your machine can do whatever they # want. You should only have this set to "" if this is a testing installation # and you cannot set this up any other way. YOU HAVE BEEN WARNED! # If you set this to anything other than "", you will need to run checksetup.pl # as} . ROOT_USER . qq{, or as a user who is a member of the specified group.\n} }, { name => 'db_driver', default => 'mysql', desc => < 'db_host', default => 'localhost', desc => "# The DNS name of the host that the database server runs on.\n" }, { name => 'db_name', default => 'bugs', desc => "# The name of the database\n" }, { name => 'db_user', default => 'bugs', desc => "# Who we connect to the database as.\n" }, { name => 'db_pass', default => '', desc => < 'db_port', default => 0, desc => < 'db_sock', default => '', desc => < 'db_check', default => 1, desc => < 'index_html', default => 0, desc => < 'cvsbin', default => \&_get_default_cvsbin, desc => < 'interdiffbin', default => \&_get_default_interdiffbin, desc => < 'diffpath', default => \&_get_default_diffpath, desc => < qw( mysqlpath contenttypes pages severities platforms opsys priorities ); sub read_localconfig { my ($include_deprecated) = @_; my $filename = bz_locations()->{'localconfig'}; my %localconfig; if (-e $filename) { my $s = new Safe; $s->rdo($filename); if ($@ || $!) { my $err_msg = $@ ? $@ : $!; die <{name}, LOCALCONFIG_VARS); push(@vars, OLD_LOCALCONFIG_VARS) if $include_deprecated; foreach my $var (@vars) { my $glob = $s->varglob($var); # We can't get the type of a variable out of a Safe automatically. # We can only get the glob itself. So we figure out its type this # way, by trying first a scalar, then an array, then a hash. # # The interesting thing is that this converts all deprecated # array or hash vars into hashrefs or arrayrefs, but that's # fine since as I write this all modern localconfig vars are # actually scalars. if (defined $$glob) { $localconfig{$var} = $$glob; } elsif (defined @$glob) { $localconfig{$var} = \@$glob; } elsif (defined %$glob) { $localconfig{$var} = \%$glob; } } } return \%localconfig; } # # This is quite tricky. But fun! # # First we read the file 'localconfig'. Then we check if the variables we # need are defined. If not, we will append the new settings to # localconfig, instruct the user to check them, and stop. # # Why do it this way? # # Assume we will enhance Bugzilla and eventually more local configuration # stuff arises on the horizon. # # But the file 'localconfig' is not in the Bugzilla CVS or tarfile. You # know, we never want to overwrite your own version of 'localconfig', so # we can't put it into the CVS/tarfile, can we? # # Now, when we need a new variable, we simply add the necessary stuff to # LOCALCONFIG_VARS. When the user gets the new version of Bugzilla from CVS and # runs checksetup, it finds out "Oh, there is something new". Then it adds # some default value to the user's local setup and informs the user to # check that to see if it is what the user wants. # # Cute, ey? # sub update_localconfig { my ($params) = @_; my $output = $params->{output} || 0; my $answer = $params->{answer} || {}; my $localconfig = read_localconfig('include deprecated'); my @new_vars; foreach my $var (LOCALCONFIG_VARS) { my $name = $var->{name}; if (!defined $localconfig->{$name}) { push(@new_vars, $name); $var->{default} = &{$var->{default}} if ref($var->{default}) eq 'CODE'; $localconfig->{$name} = $answer->{$name} || $var->{default}; } } my @old_vars; foreach my $name (OLD_LOCALCONFIG_VARS) { push(@old_vars, $name) if defined $localconfig->{$name}; } if (!$localconfig->{'interdiffbin'} && $output) { print <{'localconfig'}; if (scalar @old_vars) { my $oldstuff = join(', ', @old_vars); print <{'localconfig'}; my $fh = new IO::File($filename, '>>') || die "$filename: $!"; $fh->seek(0, SEEK_END); foreach my $var (LOCALCONFIG_VARS) { if (grep($_ eq $var->{name}, @new_vars)) { print $fh "\n", $var->{desc}, Data::Dumper->Dump([$localconfig->{$var->{name}}], ["*$var->{name}"]); } } my $newstuff = join(', ', @new_vars); print <localconfig so that it will be re-read delete Bugzilla->request_cache->{localconfig}; return { old_vars => \@old_vars, new_vars => \@new_vars }; } sub _get_default_cvsbin { return '' if ON_WINDOWS; my $cvs_executable = `which cvs`; if ($cvs_executable =~ /no cvs/ || $cvs_executable eq '') { # If which didn't find it, just set to blank $cvs_executable = ""; } else { chomp $cvs_executable; } return $cvs_executable; } sub _get_default_interdiffbin { return '' if ON_WINDOWS; my $interdiff = `which interdiff`; if ($interdiff =~ /no interdiff/ || $interdiff eq '') { # If which didn't find it, just set to blank $interdiff = ''; } else { chomp $interdiff; } return $interdiff; } sub _get_default_diffpath { return '' if ON_WINDOWS; my $diff_binaries; $diff_binaries = `which diff`; if ($diff_binaries =~ /no diff/ || $diff_binaries eq '') { # If which didn't find it, set to blank $diff_binaries = ""; } else { $diff_binaries =~ s:/diff\n$::; } return $diff_binaries; } 1; __END__ =head1 NAME Bugzilla::Install::Localconfig - Functions and variables dealing with the manipulation and creation of the F file. =head1 SYNOPSIS use Bugzilla::Install::Requirements qw(update_localconfig); update_localconfig({ output => 1, answer => \%answer }); =head1 DESCRIPTION This module is used primarily by L to create and modify the localconfig file. Most scripts should use L to access localconfig variables. =head1 CONSTANTS =over =item C An array of hashrefs. These hashrefs contain three keys: name - The name of the variable. default - The default value for the variable. Should always be something that can fit in a scalar. desc - Additional text to put in localconfig before the variable definition. Must end in a newline. Each line should start with "#" unless you have some REALLY good reason not to do that. =item C An array of names of variables. If C finds these variables defined in localconfig, it will print out a warning. =back =head1 SUBROUTINES =over =item C Description: Reads the localconfig file and returns all valid values in a hashref. Params: C<$include_deprecated> - C if you want the returned hashref to also include variables listed in C, if they exist. Generally this is only for use by C. Returns: A hashref of the localconfig variables. If an array is defined, it will be an arrayref in the returned hash. If a hash is defined, it will be a hashref in the returned hash. Only includes variables specified in C (and C if C<$include_deprecated> is specified). =item C 1, answer =E \%answer })> Description: Adds any new variables to localconfig that aren't currently defined there. Also optionally prints out a message about vars that *should* be there and aren't. Exits the program if it adds any new vars. Params: C - C if the function should display informational output and warnings. It will always display errors or any message which would cause program execution to halt. Returns: A hashref, with C being an array of names of variables that were removed, and C being an array of names of variables that were added to localconfig. =back