Bugzilla::Install::Util: code style

hinted-selects
Vitaliy Filippov 2014-10-14 16:58:57 +04:00
parent 00b9c3a608
commit 79720546a1
1 changed files with 162 additions and 108 deletions

View File

@ -1,5 +1,3 @@
# -*- 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
@ -47,7 +45,8 @@ our @EXPORT_OK = qw(
init_console
);
sub bin_loc {
sub bin_loc
{
my ($bin) = @_;
return '' if ON_WINDOWS;
# Don't print any errors from "which"
@ -62,48 +61,57 @@ sub bin_loc {
return $loc;
}
sub get_version_and_os {
sub get_version_and_os
{
# Display version information
my @os_details = POSIX::uname;
# 0 is the name of the OS, 2 is the major version,
my $os_name = $os_details[0] . ' ' . $os_details[2];
if (ON_WINDOWS) {
if (ON_WINDOWS)
{
require Win32;
$os_name = Win32::GetOSName();
}
# $os_details[3] is the minor version.
return { bz_ver => BUGZILLA_VERSION,
perl_ver => sprintf('%vd', $^V),
os_name => $os_name,
os_ver => $os_details[3] };
return {
bz_ver => BUGZILLA_VERSION,
perl_ver => sprintf('%vd', $^V),
os_name => $os_name,
os_ver => $os_details[3],
};
}
sub indicate_progress {
sub indicate_progress
{
my ($params) = @_;
my $current = $params->{current};
my $total = $params->{total};
my $every = $params->{every} || 1;
print "." if !($current % $every);
if ($current == $total || $current % ($every * 60) == 0) {
if ($current == $total || $current % ($every * 60) == 0)
{
print "$current/$total (" . int($current * 100 / $total) . "%)\n";
}
}
sub install_string {
sub install_string
{
my ($string_id, $vars) = @_;
_cache()->{install_string_path} ||= template_include_path();
my $path = _cache()->{install_string_path};
my $string_template;
# Find the first template that defines this string.
foreach my $dir (@$path) {
foreach my $dir (@$path)
{
my $base = "$dir/setup/strings";
$string_template = _get_string_from_file($string_id, "$base.txt.pl")
if !defined $string_template;
if (!defined $string_template)
{
$string_template = _get_string_from_file($string_id, "$base.txt.pl");
}
last if defined $string_template;
}
if (!defined $string_template)
{
# Don't throw an error, it's a stupid way -- <vitalif@yourcmc.ru>
@ -115,16 +123,17 @@ sub install_string {
$vars ||= {};
my @replace_keys = keys %$vars;
foreach my $key (@replace_keys) {
foreach my $key (@replace_keys)
{
my $replacement = $vars->{$key};
die "'$key' in '$string_id' is tainted: '$replacement'"
if tainted($replacement);
die "'$key' in '$string_id' is tainted: '$replacement'" if tainted($replacement);
# We don't want people to start getting clever and inserting
# ##variable## into their values. So we check if any other
# key is listed in the *replacement* string, before doing
# the replacement. This is mostly to protect programmers from
# making mistakes.
if (grep($replacement =~ /##$key##/, @replace_keys)) {
if (grep($replacement =~ /##$key##/, @replace_keys))
{
die "Unsafe replacement for '$key' in '$string_id': '$replacement'";
}
$string_template =~ s/\Q##$key##\E/$replacement/g;
@ -133,15 +142,18 @@ sub install_string {
return $string_template;
}
sub include_languages {
sub include_languages
{
# If we are in CGI mode (not in checksetup.pl) and if the function has
# been called without any parameter, then we cache the result of this
# function in Bugzilla->request_cache. This is done to improve the
# performance of the template processing.
my $to_be_cached = 0;
if (not @_) {
if (not @_)
{
my $cache = _cache();
if (exists $cache->{include_languages}) {
if (exists $cache->{include_languages})
{
return @{ $cache->{include_languages} };
}
$to_be_cached = 1;
@ -156,43 +168,48 @@ sub include_languages {
# $params->{only_language}. The languages we support are those
# specified in $params->{use_languages}. Otherwise we support every
# language installed in the template/ directory.
my @wanted;
if ($params->{only_language}) {
if ($params->{only_language})
{
# We can pass several languages at once as an arrayref
# or a single language.
if (ref $params->{only_language}) {
if (ref $params->{only_language})
{
@wanted = @{ $params->{only_language} };
}
else {
else
{
@wanted = ($params->{only_language});
}
}
else {
@wanted = _sort_accept_language($ENV{'HTTP_ACCEPT_LANGUAGE'} || '');
else
{
@wanted = _sort_accept_language($ENV{HTTP_ACCEPT_LANGUAGE} || '');
# Don't use the cookie if we are in "checksetup.pl". The test
# with $ENV{'SERVER_SOFTWARE'} is the same as in
# with $ENV{SERVER_SOFTWARE} is the same as in
# Bugzilla:Util::i_am_cgi.
if (exists $ENV{'SERVER_SOFTWARE'}) {
my $cgi = Bugzilla->cgi;
if (defined (my $lang = Bugzilla->cookies->{LANG})) {
unshift @wanted, $lang;
}
if (exists $ENV{SERVER_SOFTWARE} && defined (my $lang = Bugzilla->cookies->{LANG}))
{
unshift @wanted, $lang;
}
}
my @supported;
if (defined $params->{use_languages}) {
if (defined $params->{use_languages})
{
@supported = @{$params->{use_languages}};
}
else {
my @dirs = glob(bz_locations()->{'templatedir'} . "/*");
else
{
my @dirs = glob(bz_locations()->{templatedir} . "/*");
@dirs = map(basename($_), @dirs);
@supported = grep($_ ne 'CVS', @dirs);
}
my @usedlanguages;
foreach my $wanted (@wanted) {
foreach my $wanted (@wanted)
{
# If we support the language we want, or *any version* of
# the language we want, it gets pushed into @usedlanguages.
#
@ -200,20 +217,23 @@ sub include_languages {
# 'en-uk', but not the other way around. (This is unfortunately
# not very clearly stated in those RFC; see comment just over 14.5
# in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
if(my @found = grep /^\Q$wanted\E(-.+)?$/i, @supported) {
if (my @found = grep /^\Q$wanted\E(-.+)?$/i, @supported)
{
push (@usedlanguages, @found);
}
}
# We always include English at the bottom if it's not there, even if
# somebody removed it from use_languages.
if (!grep($_ eq 'en', @usedlanguages)) {
if (!grep($_ eq 'en', @usedlanguages))
{
push(@usedlanguages, 'en');
}
# Cache the result if we are in CGI mode and called without parameter
# (see the comment at the top of this function).
if ($to_be_cached) {
if ($to_be_cached)
{
_cache()->{include_languages} = \@usedlanguages;
}
@ -221,18 +241,20 @@ sub include_languages {
}
# Used by template_include_path
sub _template_lang_directories {
sub _template_lang_directories
{
my ($languages, $templatedir) = @_;
my @add = qw(custom default);
my $project = bz_locations->{'project'};
my $project = bz_locations->{project};
unshift(@add, $project) if $project;
my @result;
foreach my $lang (@$languages) {
foreach my $dir (@add) {
foreach my $lang (@$languages)
{
foreach my $dir (@add)
{
my $full_dir = "$templatedir/$lang/$dir";
if (-d $full_dir) {
if (-d $full_dir)
{
trick_taint($full_dir);
push(@result, $full_dir);
}
@ -245,7 +267,6 @@ sub _template_lang_directories {
sub _template_base_directories
{
my @template_dirs;
Bugzilla::Extension::load_all();
my $dir;
foreach (Bugzilla::Extension::loaded())
@ -256,8 +277,7 @@ sub _template_base_directories
push @template_dirs, $dir;
}
}
push(@template_dirs, bz_locations()->{'templatedir'});
push @template_dirs, bz_locations()->{templatedir};
return \@template_dirs;
}
@ -267,18 +287,19 @@ sub template_include_path
my @used_languages = include_languages($params);
# Now, we add template directories in the order they will be searched:
my $template_dirs = _template_base_directories();
my @include_path;
foreach my $template_dir (@$template_dirs) {
my @lang_dirs = _template_lang_directories(\@used_languages,
$template_dir);
foreach my $template_dir (@$template_dirs)
{
my @lang_dirs = _template_lang_directories(\@used_languages, $template_dir);
# Hooks get each set of extension directories separately.
if ($params->{hook}) {
push(@include_path, \@lang_dirs) if @lang_dirs;
if ($params->{hook})
{
push @include_path, \@lang_dirs if @lang_dirs;
}
# Whereas everything else just gets a whole INCLUDE_PATH.
else {
push(@include_path, @lang_dirs);
else
{
push @include_path, @lang_dirs;
}
}
# Allow to fallback to full template path - not a security risk,
@ -289,7 +310,8 @@ sub template_include_path
# This is taken straight from Sort::Versions 1.5, which is not included
# with perl by default.
sub vers_cmp {
sub vers_cmp
{
my ($a, $b) = @_;
$a = '' if !defined $a;
$b = '' if !defined $b;
@ -302,28 +324,47 @@ sub vers_cmp {
my @B = ($b =~ /([-.]|\d+|[^-.\d]+)/g);
my ($A, $B);
while (@A and @B) {
while (@A && @B)
{
$A = shift @A;
$B = shift @B;
if ($A eq '-' and $B eq '-') {
if ($A eq '-' && $B eq '-')
{
next;
} elsif ( $A eq '-' ) {
}
elsif ($A eq '-')
{
return -1;
} elsif ( $B eq '-') {
}
elsif ($B eq '-')
{
return 1;
} elsif ($A eq '.' and $B eq '.') {
}
elsif ($A eq '.' && $B eq '.')
{
next;
} elsif ( $A eq '.' ) {
}
elsif ($A eq '.')
{
return -1;
} elsif ( $B eq '.' ) {
}
elsif ($B eq '.')
{
return 1;
} elsif ($A =~ /^\d+$/ and $B =~ /^\d+$/) {
if ($A =~ /^0/ || $B =~ /^0/) {
}
elsif ($A =~ /^\d+$/ && $B =~ /^\d+$/)
{
if ($A =~ /^0/ || $B =~ /^0/)
{
return $A cmp $B if $A cmp $B;
} else {
}
else
{
return $A <=> $B if $A <=> $B;
}
} else {
}
else
{
$A = uc $A;
$B = uc $B;
return $A cmp $B if $A cmp $B;
@ -337,9 +378,9 @@ sub vers_cmp {
######################
# Used by install_string
sub _get_string_from_file {
sub _get_string_from_file
{
my ($string_id, $file) = @_;
return undef if !-e $file;
my $safe = new Safe;
$safe->rdo($file);
@ -350,80 +391,87 @@ sub _get_string_from_file {
# Make an ordered list out of a HTTP Accept-Language header (see RFC 2616, 14.4)
# We ignore '*' and <language-range>;q=0
# For languages with the same priority q the order remains unchanged.
sub _sort_accept_language {
sub sortQvalue { $b->{'qvalue'} <=> $a->{'qvalue'} }
sub _sort_accept_language
{
my $accept_language = $_[0];
# clean up string.
$accept_language =~ s/[^A-Za-z;q=0-9\.\-,]//g;
my @qlanguages;
my @languages;
foreach(split /,/, $accept_language) {
if (m/([A-Za-z\-]+)(?:;q=(\d(?:\.\d+)))?/) {
foreach(split /,/, $accept_language)
{
if (m/([A-Za-z\-]+)(?:;q=(\d(?:\.\d+)))?/)
{
my $lang = $1;
my $qvalue = $2;
$qvalue = 1 if not defined $qvalue;
next if $qvalue == 0;
$qvalue = 1 if $qvalue > 1;
push(@qlanguages, {'qvalue' => $qvalue, 'language' => $lang});
push @qlanguages, { qvalue => $qvalue, language => $lang };
}
}
return map($_->{'language'}, (sort sortQvalue @qlanguages));
return map($_->{language}, (sort { $b->{qvalue} <=> $a->{qvalue} } @qlanguages));
}
sub get_console_locale {
sub get_console_locale
{
require Locale::Language;
my $locale = setlocale(LC_CTYPE);
my $language;
# Some distros set e.g. LC_CTYPE = fr_CH.UTF-8. We clean it up.
if ($locale =~ /^([^\.]+)/) {
if ($locale =~ /^([^\.]+)/)
{
$locale = $1;
}
$locale =~ s/_/-/;
# It's pretty sure that there is no language pack of the form fr-CH
# installed, so we also include fr as a wanted language.
if ($locale =~ /^(\S+)\-/) {
if ($locale =~ /^(\S+)\-/)
{
$language = $1;
$locale .= ",$language";
}
else {
else
{
$language = $locale;
}
# Some OSs or distributions may have setlocale return a string of the form
# German_Germany.1252 (this example taken from a Windows XP system), which
# is unsuitable for our needs because Bugzilla works on language codes.
# We try and convert them here.
if ($language = Locale::Language::language2code($language)) {
if ($language = Locale::Language::language2code($language))
{
$locale .= ",$language";
}
return $locale;
}
sub init_console {
sub init_console
{
eval { ON_WINDOWS && require Win32::Console::ANSI; };
$ENV{'ANSI_COLORS_DISABLED'} = 1 if ($@ || !-t *STDOUT);
$ENV{'HTTP_ACCEPT_LANGUAGE'} ||= get_console_locale();
$ENV{ANSI_COLORS_DISABLED} = 1 if ($@ || !-t *STDOUT);
$ENV{HTTP_ACCEPT_LANGUAGE} ||= get_console_locale();
prevent_windows_dialog_boxes();
}
sub prevent_windows_dialog_boxes {
sub prevent_windows_dialog_boxes
{
# This code comes from http://bugs.activestate.com/show_bug.cgi?id=82183
# and prevents Perl modules from popping up dialog boxes, particularly
# during checksetup (since loading DBD::Oracle during checksetup when
# Oracle isn't installed causes a scary popup and pauses checksetup).
#
# Win32::API ships with ActiveState by default, though there could
# Win32::API ships with ActiveState by default, though there could
# theoretically be a Windows installation without it, I suppose.
if (ON_WINDOWS and eval { require Win32::API }) {
if (ON_WINDOWS and eval { require Win32::API })
{
# Call kernel32.SetErrorMode with arguments that mean:
# "The system does not display the critical-error-handler message box.
# Instead, the system sends the error to the calling process." and
# "A child process inherits the error mode of its parent process."
my $SetErrorMode = Win32::API->new('kernel32', 'SetErrorMode',
'I', 'I');
my $SetErrorMode = Win32::API->new('kernel32', 'SetErrorMode', 'I', 'I');
my $SEM_FAILCRITICALERRORS = 0x0001;
my $SEM_NOGPFAULTERRORBOX = 0x0002;
$SetErrorMode->Call($SEM_FAILCRITICALERRORS | $SEM_NOGPFAULTERRORBOX);
@ -433,10 +481,12 @@ sub prevent_windows_dialog_boxes {
# This is like request_cache, but it's used only by installation code
# for checksetup.pl and things like that.
our $_cache = {};
sub _cache {
sub _cache
{
# If the normal request_cache is available (which happens any time
# after the requirements phase) then we should use that.
if (eval { Bugzilla->request_cache; }) {
if (eval { Bugzilla->request_cache; })
{
return Bugzilla->request_cache;
}
return $_cache;
@ -446,7 +496,8 @@ sub _cache {
# Copied from Bugzilla::Util #
##############################
sub trick_taint {
sub trick_taint
{
require Carp;
Carp::confess("Undef to trick_taint") unless defined $_[0];
my $match = $_[0] =~ /^(.*)$/s;
@ -454,15 +505,18 @@ sub trick_taint {
return (defined($_[0]));
}
sub trim {
sub trim
{
my ($str) = @_;
if ($str) {
$str =~ s/^\s+//g;
$str =~ s/\s+$//g;
if ($str)
{
$str =~ s/^\s+//g;
$str =~ s/\s+$//g;
}
return $str;
}
1;
__END__
=head1 NAME
@ -633,8 +687,8 @@ in their browser, usually), and extensions are sorted alphabetically.
=item C<include_languages>
Used by L<Bugzilla::Template> to determine the languages' list which
are compiled with the browser's I<Accept-Language> and the languages
Used by L<Bugzilla::Template> to determine the languages' list which
are compiled with the browser's I<Accept-Language> and the languages
of installed templates.
=item C<vers_cmp>