Config.pm 11.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
# -*- 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 Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
#                 Dawn Endico <endico@mozilla.org>
#                 Dan Mosedale <dmose@mozilla.org>
#                 Joe Robins <jmrobins@tgix.com>
#                 Jake <jake@bugzilla.org>
#                 J. Paul Reed <preed@sigkill.com>
#                 Bradley Baetz <bbaetz@student.usyd.edu.au>
#                 Christopher Aillon <christopher@aillon.com>
28
#                 Erik Stambaugh <erik@dasbistro.com>
29
#                 Frédéric Buclin <LpSolit@gmail.com>
30 31 32 33 34 35 36

package Bugzilla::Config;

use strict;

use base qw(Exporter);

37 38 39 40 41 42 43 44 45 46
# Under mod_perl, get this from a .htaccess config variable,
# and/or default from the current 'real' dir
# At some stage after this, it may be possible for these dir locations
# to go into localconfig. localconfig can't be specified in a config file,
# except possibly with mod_perl. If you move localconfig, you need to change
# the define here.
# $libpath is really only for mod_perl; its not yet possible to move the
# .pms elsewhere.
# $webdotdir must be in the webtree somewhere. Even if you use a local dot,
# we output images to there. Also, if $webdot dir is not relative to the
47
# bugzilla root directory, you'll need to change showdependencygraph.cgi to
48 49
# set image_url to the correct location.
# The script should really generate these graphs directly...
50
# Note that if $libpath is changed, some stuff will break, notably dependency
51 52 53
# graphs (since the path will be wrong in the HTML). This will be fixed at
# some point.

54
# constant paths
55 56
our $libpath = '.';
our $templatedir = "$libpath/template";
57 58 59 60 61 62 63 64 65 66 67 68 69 70

# variable paths
our $project;
our $localconfig;
our $datadir;
if ($ENV{'PROJECT'} && $ENV{'PROJECT'} =~ /^(\w+)$/) {
    $project = $1;
    $localconfig = "$libpath/localconfig.$project";
    $datadir = "$libpath/data/$project";
} else {
    $localconfig = "$libpath/localconfig";
    $datadir = "$libpath/data";
}
our $attachdir = "$datadir/attachments";
71
our $webdotdir = "$datadir/webdot";
72
our $extensionsdir = "$libpath/extensions";
73

74 75
our @parampanels = ();

76 77 78 79 80 81 82 83
# Module stuff
@Bugzilla::Config::EXPORT = qw(Param);

# Don't export localvars by default - people should have to explicitly
# ask for it, as a (probably futile) attempt to stop code using it
# when it shouldn't
# ChmodDataFile is here until that stuff all moves out of globals.pl
# into this file
84 85
@Bugzilla::Config::EXPORT_OK = qw(ChmodDataFile);

86 87
%Bugzilla::Config::EXPORT_TAGS =
  (
88
   admin => [qw(UpdateParams SetParam WriteParams)],
89
   db => [qw($db_driver $db_host $db_port $db_name $db_user $db_pass $db_sock)],
90
   locations => [qw($libpath $localconfig $attachdir $datadir $templatedir
91
                    $webdotdir $project $extensionsdir)],
92
   params => [qw(@parampanels)],
93
  );
94
Exporter::export_ok_tags('admin', 'db', 'locations', 'params');
95 96

# Bugzilla version
97
$Bugzilla::Config::VERSION = "2.23.1+";
98 99

use vars qw(@param_list);
100 101 102 103 104 105 106 107 108 109 110

# Data::Dumper is required as needed, below. The problem is that then when
# the code locally sets $Data::Dumper::Foo, this triggers 'used only once'
# warnings.
# We can't predeclare another package's vars, though, so just use them
{
    local $Data::Dumper::Sortkeys;
    local $Data::Dumper::Terse;
    local $Data::Dumper::Indent;
}

111
# INITIALISATION CODE
112
do $localconfig;
113
my %params;
114 115 116 117 118 119 120 121 122 123 124 125
# Load in the param definitions
foreach my $item ((glob "$libpath/Bugzilla/Config/*.pm")) {
    $item =~ m#/([^/]+)\.pm$#;
    my $module = $1;
    next if ($module eq 'Common');
    require "Bugzilla/Config/$module.pm";
    my @new_param_list = "Bugzilla::Config::$module"->get_param_list();
    foreach my $item (@new_param_list) {
        $params{$item->{'name'}} = $item;
    }
    push(@parampanels, $module);
    push(@param_list, @new_param_list);
126 127 128 129 130 131 132 133 134
}

# END INIT CODE

# Subroutines go here

sub Param {
    my ($param) = @_;

135 136
    my %param_values = %{Bugzilla->params};

137
    # By this stage, the param must be in the hash
138
    die "Can't find param named $param" unless (exists $params{$param});
139

140 141 142
    # When module startup code runs (which is does even via -c, when using
    # |use|), we may try to grab params which don't exist yet. This affects
    # tests, so have this as a fallback for the -c case
143 144
    return $params{$param}->{default} 
        if ($^C && not exists $param_values{$param});
145 146

    # If we have a value for the param, return it
147
    return $param_values{$param} if exists $param_values{$param};
148 149

    # Else error out
150
    die "No value for param $param (try running checksetup.pl again)";
151 152 153 154 155 156 157 158 159 160
}

sub SetParam {
    my ($name, $value) = @_;

    die "Unknown param $name" unless (exists $params{$name});

    my $entry = $params{$name};

    # sanity check the value
161 162

    # XXX - This runs the checks. Which would be good, except that
163 164
    # check_shadowdb creates the database as a side effect, and so the
    # checker fails the second time around...
165
    if ($name ne 'shadowdb' && exists $entry->{'checker'}) {
166 167 168 169
        my $err = $entry->{'checker'}->($value, $entry);
        die "Param $name is not valid: $err" unless $err eq '';
    }

170
    Bugzilla->params->{$name} = $value;
171 172 173 174 175 176 177 178 179
}

sub UpdateParams {
    # --- PARAM CONVERSION CODE ---

    # Note that this isn't particuarly 'clean' in terms of separating
    # the backend code (ie this) from the actual params.
    # We don't care about that, though

180 181
    my $param = Bugzilla->params;

182 183
    # Old bugzilla versions stored the version number in the params file
    # We don't want it, so get rid of it
184
    delete $param->{'version'};
185

186
    # Change from usebrowserinfo to defaultplatform/defaultopsys combo
187 188 189 190
    if (exists $param->{'usebrowserinfo'}) {
        if (!$param->{'usebrowserinfo'}) {
            if (!exists $param->{'defaultplatform'}) {
                $param->{'defaultplatform'} = 'Other';
191
            }
192 193
            if (!exists $param->{'defaultopsys'}) {
                $param->{'defaultopsys'} = 'Other';
194 195
            }
        }
196
        delete $param->{'usebrowserinfo'};
197 198
    }

199
    # Change from a boolean for quips to multi-state
200 201 202
    if (exists $param->{'usequip'} && !exists $param->{'enablequips'}) {
        $param->{'enablequips'} = $param->{'usequip'} ? 'on' : 'off';
        delete $param->{'usequip'};
203 204
    }

205 206
    # Change from old product groups to controls for group_control_map
    # 2002-10-14 bug 147275 bugreport@peshkin.net
207 208
    if (exists $param->{'usebuggroups'} && !exists $param->{'makeproductgroups'}) {
        $param->{'makeproductgroups'} = $param->{'usebuggroups'};
209
    }
210 211 212
    if (exists $param->{'usebuggroupsentry'} 
       && !exists $param->{'useentrygroupdefault'}) {
        $param->{'useentrygroupdefault'} = $param->{'usebuggroupsentry'};
213 214
    }

215
    # Modularise auth code
216 217
    if (exists $param->{'useLDAP'} && !exists $param->{'loginmethod'}) {
        $param->{'loginmethod'} = $param->{'useLDAP'} ? "LDAP" : "DB";
218 219
    }

220
    # set verify method to whatever loginmethod was
221 222 223
    if (exists $param->{'loginmethod'} && !exists $param->{'user_verify_class'}) {
        $param->{'user_verify_class'} = $param->{'loginmethod'};
        delete $param->{'loginmethod'};
224 225
    }

226 227
    # Remove quip-display control from parameters
    # and give it to users via User Settings (Bug 41972)
228 229
    if ( exists $param->{'enablequips'} 
         && !exists $param->{'quip_list_entry_control'}) 
230 231
    {
        my $new_value;
232 233 234 235 236 237
        ($param->{'enablequips'} eq 'on')       && do {$new_value = 'open';};
        ($param->{'enablequips'} eq 'approved') && do {$new_value = 'moderated';};
        ($param->{'enablequips'} eq 'frozen')   && do {$new_value = 'closed';};
        ($param->{'enablequips'} eq 'off')      && do {$new_value = 'closed';};
        $param->{'quip_list_entry_control'} = $new_value;
        delete $param->{'enablequips'};
238 239
    }

240 241 242 243
    # --- DEFAULTS FOR NEW PARAMS ---

    foreach my $item (@param_list) {
        my $name = $item->{'name'};
244
        $param->{$name} = $item->{'default'} unless exists $param->{$name};
245 246 247 248 249 250 251
    }

    # --- REMOVE OLD PARAMS ---

    my @oldparams = ();

    # Remove any old params
252
    foreach my $item (keys %$param) {
253
        if (!grep($_ eq $item, map ($_->{'name'}, @param_list))) {
254 255
            require Data::Dumper;

256 257
            local $Data::Dumper::Terse = 1;
            local $Data::Dumper::Indent = 0;
258 259
            push (@oldparams, [$item, Data::Dumper->Dump([$param->{$item}])]);
            delete $param->{$item};
260 261 262 263 264 265
        }
    }

    return @oldparams;
}

266 267
sub WriteParams {
    require Data::Dumper;
268

269 270 271
    # This only has an affect for Data::Dumper >= 2.12 (ie perl >= 5.8.0)
    # Its just cosmetic, though, so that doesn't matter
    local $Data::Dumper::Sortkeys = 1;
272

273
    require File::Temp;
274
    my ($fh, $tmpname) = File::Temp::tempfile('params.XXXXX',
275
                                              DIR => $datadir );
276

277
    print $fh (Data::Dumper->Dump([Bugzilla->params], ['*param']))
278 279 280 281
      || die "Can't write param file: $!";

    close $fh;

282 283
    rename $tmpname, "$datadir/params"
      || die "Can't rename $tmpname to $datadir/params: $!";
284

285
    ChmodDataFile("$datadir/params", 0666);
286 287
}

288 289
# Some files in the data directory must be world readable if and only if
# we don't have a webserver group. Call this function to do this.
290 291 292 293 294 295 296
# This will become a private function once all the datafile handling stuff
# moves into this package

# This sub is not perldoc'd for that reason - noone should know about it
sub ChmodDataFile {
    my ($file, $mask) = @_;
    my $perm = 0770;
297
    if ((stat($datadir))[2] & 0002) {
298 299 300 301 302 303
        $perm = 0777;
    }
    $perm = $perm & $mask;
    chmod $perm,$file;
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
1;

__END__

=head1 NAME

Bugzilla::Config - Configuration parameters for Bugzilla

=head1 SYNOPSIS

  # Getting parameters
  use Bugzilla::Config;

  my $fooSetting = Param('foo');

  # Administration functions
  use Bugzilla::Config qw(:admin);

  my @removed_params = UpgradeParams();
  SetParam($param, $value);
  WriteParams();

  # Localconfig variables may also be imported
  use Bugzilla::Config qw(:db);
  print "Connecting to $db_name as $db_user with $db_pass\n";

=head1 DESCRIPTION

This package contains ways to access Bugzilla configuration parameters.

=head1 FUNCTIONS

=head2 Parameters

Parameters can be set, retrieved, and updated.

=over 4

=item C<Param($name)>

Returns the Param with the specified name. Either a string, or, in the case
of multiple-choice parameters, an array reference.

=item C<SetParam($name, $value)>

Sets the param named $name to $value. Values are checked using the checker
function for the given param if one exists.

=item C<UpdateParams()>

Updates the parameters, by transitioning old params to new formats, setting
defaults for new params, and removing obsolete ones.

Any removed params are returned in a list, with elements [$item, $oldvalue]
where $item is the entry in the param list.

=item C<WriteParams()>

Writes the parameters to disk.

364 365
=back

366
=over
367 368 369 370 371 372 373 374 375 376 377 378

=item *

The new value for the parameter

=item *

A reference to the entry in the param list for this parameter

Functions should return error text, or the empty string if there was no error.

=back