зеркало из https://github.com/mozilla/gecko-dev.git
Bug 330487: Automatic Update Notification for Bugzilla - Patch by Fr�d�ric Buclin <LpSolit@gmail.com> r=mkanat a=justdave
This commit is contained in:
Родитель
b6ddf6008a
Коммит
a836e8c466
|
@ -64,7 +64,7 @@ use base qw(Exporter);
|
|||
check_sslbase check_priority check_severity check_platform
|
||||
check_opsys check_shadowdb check_urlbase check_webdotbase
|
||||
check_netmask check_user_verify_class check_image_converter
|
||||
check_languages check_mail_delivery_method
|
||||
check_languages check_mail_delivery_method check_notification
|
||||
);
|
||||
|
||||
# Checking functions for the various values
|
||||
|
@ -303,6 +303,20 @@ sub check_mail_delivery_method {
|
|||
return "";
|
||||
}
|
||||
|
||||
sub check_notification {
|
||||
my $option = shift;
|
||||
my @current_version =
|
||||
($Bugzilla::Config::VERSION =~ m/^(\d+)\.(\d+)(?:(rc|\.)(\d+))?\+?$/);
|
||||
if ($current_version[1] % 2 && $option eq 'stable_branch_release') {
|
||||
return "You are currently running a development snapshot, and so your " .
|
||||
"installation is not based on a branch. If you want to be notified " .
|
||||
"about the next stable release, you should select " .
|
||||
"'latest_stable_release' instead";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
# OK, here are the parameter definitions themselves.
|
||||
#
|
||||
# Each definition is a hash with keys:
|
||||
|
|
|
@ -103,6 +103,15 @@ sub get_param_list {
|
|||
name => 'shutdownhtml',
|
||||
type => 'l',
|
||||
default => ''
|
||||
},
|
||||
|
||||
{
|
||||
name => 'upgrade_notification',
|
||||
type => 's',
|
||||
choices => ['development_snapshot', 'latest_stable_release',
|
||||
'stable_branch_release', 'disabled'],
|
||||
default => 'latest_stable_release',
|
||||
checker => \&check_notification
|
||||
} );
|
||||
return @param_list;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
# -*- 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.
|
||||
#
|
||||
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
|
||||
|
||||
package Bugzilla::Update;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Config qw($datadir);
|
||||
|
||||
use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml';
|
||||
use constant LOCAL_FILE => "/bugzilla-update.xml"; # Relative to $datadir.
|
||||
use constant TIME_INTERVAL => 604800; # Default is one week, in seconds.
|
||||
use constant TIMEOUT => 5; # Number of seconds before timeout.
|
||||
|
||||
# Look for new releases and notify logged in administrators about them.
|
||||
sub get_notifications {
|
||||
return if (Bugzilla->params->{'upgrade_notification'} eq 'disabled');
|
||||
|
||||
# If the XML::Twig module is missing, we won't be able to parse
|
||||
# the XML file. So there is no need to go further.
|
||||
eval("require XML::Twig");
|
||||
return if $@;
|
||||
|
||||
my $local_file = $datadir . LOCAL_FILE;
|
||||
# Update the local XML file if this one doesn't exist or if
|
||||
# the last modification time (stat[9]) is older than TIME_INTERVAL.
|
||||
if (!-e $local_file || (time() - (stat($local_file))[9] > TIME_INTERVAL)) {
|
||||
# Are we sure we didn't try to refresh this file already
|
||||
# but we failed because we cannot modify its timestamp?
|
||||
my $can_alter = 1;
|
||||
if (-e $local_file) {
|
||||
# Try to alter its last modification time.
|
||||
$can_alter = utime(undef, undef, $local_file);
|
||||
}
|
||||
if ($can_alter) {
|
||||
_synchronize_data();
|
||||
}
|
||||
else {
|
||||
return {'error' => 'no_update', 'xml_file' => $local_file};
|
||||
}
|
||||
}
|
||||
|
||||
# If we cannot access the local XML file, ignore it.
|
||||
return {'error' => 'no_access', 'xml_file' => $local_file} unless (-r $local_file);
|
||||
|
||||
my $twig = XML::Twig->new();
|
||||
$twig->safe_parsefile($local_file);
|
||||
# If the XML file is invalid, return.
|
||||
return {'error' => 'corrupted', 'xml_file' => $local_file} if $@;
|
||||
my $root = $twig->root;
|
||||
|
||||
my @releases;
|
||||
foreach my $branch ($root->children('branch')) {
|
||||
my $release = {
|
||||
'branch_ver' => $branch->{'att'}->{'id'},
|
||||
'latest_ver' => $branch->{'att'}->{'vid'},
|
||||
'status' => $branch->{'att'}->{'status'},
|
||||
'url' => $branch->{'att'}->{'url'},
|
||||
'date' => $branch->{'att'}->{'date'}
|
||||
};
|
||||
push(@releases, $release);
|
||||
}
|
||||
|
||||
# On which branch is the current installation running?
|
||||
my @current_version =
|
||||
($Bugzilla::Config::VERSION =~ m/^(\d+)\.(\d+)(?:(rc|\.)(\d+))?\+?$/);
|
||||
|
||||
my @release;
|
||||
if (Bugzilla->params->{'upgrade_notification'} eq 'development_snapshot') {
|
||||
@release = grep {$_->{'status'} eq 'development'} @releases;
|
||||
}
|
||||
elsif (Bugzilla->params->{'upgrade_notification'} eq 'latest_stable_release') {
|
||||
@release = grep {$_->{'status'} eq 'stable'} @releases;
|
||||
}
|
||||
elsif (Bugzilla->params->{'upgrade_notification'} eq 'stable_branch_release') {
|
||||
# We want the latest stable version for the current branch.
|
||||
# If we are running a development snapshot, we won't match anything.
|
||||
my $branch_version = $current_version[0] . '.' . $current_version[1];
|
||||
|
||||
# We do a string comparison instead of a numerical one, because
|
||||
# e.g. 2.2 == 2.20, but 2.2 ne 2.20 (and 2.2 is indeed much older).
|
||||
@release = grep {$_->{'branch_ver'} eq $branch_version} @releases;
|
||||
|
||||
# If the branch is now closed, we should strongly suggest
|
||||
# to upgrade to the latest stable release available.
|
||||
if (scalar(@release) && $release[0]->{'status'} eq 'closed') {
|
||||
@release = grep {$_->{'status'} eq 'stable'} @releases;
|
||||
return {'data' => $release[0], 'deprecated' => $branch_version};
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Unknown parameter.
|
||||
return {'error' => 'unknown_parameter'};
|
||||
}
|
||||
|
||||
# Return if no new release is available.
|
||||
return unless scalar(@release);
|
||||
|
||||
# Only notify the administrator if the latest version available
|
||||
# is newer than the current one.
|
||||
my @new_version =
|
||||
($release[0]->{'latest_ver'} =~ m/^(\d+)\.(\d+)(?:(rc|\.)(\d+))?\+?$/);
|
||||
|
||||
# We convert release candidates 'rc' to integers (rc ? 0 : 1) in order
|
||||
# to compare versions easily.
|
||||
$current_version[2] = ($current_version[2] && $current_version[2] eq 'rc') ? 0 : 1;
|
||||
$new_version[2] = ($new_version[2] && $new_version[2] eq 'rc') ? 0 : 1;
|
||||
|
||||
my $is_newer = _compare_versions(\@current_version, \@new_version);
|
||||
return ($is_newer == 1) ? {'data' => $release[0]} : undef;
|
||||
}
|
||||
|
||||
sub _synchronize_data {
|
||||
eval("require LWP::UserAgent");
|
||||
return if $@;
|
||||
|
||||
my $local_file = $datadir . LOCAL_FILE;
|
||||
|
||||
my $ua = LWP::UserAgent->new();
|
||||
$ua->timeout(TIMEOUT);
|
||||
$ua->protocols_allowed(['http', 'https']);
|
||||
$ua->mirror(REMOTE_FILE, $local_file);
|
||||
|
||||
# $ua->mirror() forces the modification time of the local XML file
|
||||
# to match the modification time of the remote one.
|
||||
# So we have to update it manually to reflect that a newer version
|
||||
# of the file has effectively been requested. This will avoid
|
||||
# any new download for the next TIME_INTERVAL.
|
||||
utime(undef, undef, $local_file);
|
||||
}
|
||||
|
||||
sub _compare_versions {
|
||||
my ($old_ver, $new_ver) = @_;
|
||||
while (scalar(@$old_ver) && scalar(@$new_ver)) {
|
||||
my $old = shift(@$old_ver);
|
||||
my $new = shift(@$new_ver);
|
||||
return $new <=> $old if ($new <=> $old);
|
||||
}
|
||||
return scalar(@$new_ver) <=> scalar(@$old_ver);
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Update - Update routines for Bugzilla
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Bugzilla::Update;
|
||||
|
||||
# Get information about new releases
|
||||
my $new_release = Bugzilla::Update::get_notifications();
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains all required routines to notify you
|
||||
about new releases. It downloads an XML file from bugzilla.org
|
||||
and parses it, in order to display information based on your
|
||||
preferences. Absolutely no information about the Bugzilla version
|
||||
you are running is sent to bugzilla.org.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item C<get_notifications()>
|
||||
|
||||
Description: This function informs you about new releases, if any.
|
||||
|
||||
Params: None.
|
||||
|
||||
Returns: On success, a reference to a hash with data about
|
||||
new releases, if any.
|
||||
On failure, a reference to a hash with the reason
|
||||
of the failure and the name of the unusable XML file.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
|
@ -355,6 +355,7 @@ my %ppm_modules = (
|
|||
'Mail::Base64' => 'MIME-Base64',
|
||||
'MIME::Tools' => 'MIME-Tools',
|
||||
'XML::Twig' => 'XML-Twig',
|
||||
'LWP::UserAgent' => 'LWP-UserAgent'
|
||||
);
|
||||
|
||||
sub install_command {
|
||||
|
@ -392,6 +393,7 @@ print "\nThe following Perl modules are optional:\n" unless $silent;
|
|||
my $gd = have_vers("GD","1.20");
|
||||
my $chartbase = have_vers("Chart::Base","1.0");
|
||||
my $xmlparser = have_vers("XML::Twig",0);
|
||||
my $lwp_ua = have_vers("LWP::UserAgent",0);
|
||||
my $gdgraph = have_vers("GD::Graph",0);
|
||||
my $gdtextalign = have_vers("GD::Text::Align",0);
|
||||
my $patchreader = have_vers("PatchReader","0.9.4");
|
||||
|
@ -420,6 +422,12 @@ if (!$xmlparser && !$silent) {
|
|||
"the XML::Twig module by running (as $::root):\n\n",
|
||||
" " . install_command("XML::Twig") . "\n\n";
|
||||
}
|
||||
if (!$lwp_ua && !$silent) {
|
||||
print "If you want to use the automatic update notification feature\n",
|
||||
"you will need to install the LWP::UserAgent module by running\n",
|
||||
"(as $::root):\n\n",
|
||||
" " . install_command("LWP::UserAgent") . "\n\n";
|
||||
}
|
||||
if (!$imagemagick && !$silent) {
|
||||
print "If you want to convert BMP image attachments to PNG to conserve\n",
|
||||
"disk space, you will need to install the ImageMagick application\n",
|
||||
|
@ -1420,6 +1428,8 @@ if ($^O !~ /MSWin32/i) {
|
|||
fixPerms($webdotdir, $<, $webservergid, 007, 1);
|
||||
fixPerms("$webdotdir/.htaccess", $<, $webservergid, 027);
|
||||
fixPerms("$datadir/params", $<, $webservergid, 017);
|
||||
# The web server must be the owner of bugzilla-update.xml.
|
||||
fixPerms("$datadir/bugzilla-update.xml", $webservergid, $webservergid, 017);
|
||||
fixPerms('*', $<, $webservergid, 027);
|
||||
fixPerms('Bugzilla', $<, $webservergid, 027, 1);
|
||||
fixPerms($templatedir, $<, $webservergid, 027, 1);
|
||||
|
@ -1447,6 +1457,7 @@ if ($^O !~ /MSWin32/i) {
|
|||
chmod 01777, $webdotdir;
|
||||
fixPerms("$webdotdir/.htaccess", $<, $gid, 022);
|
||||
fixPerms("$datadir/params", $<, $gid, 011);
|
||||
fixPerms("$datadir/bugzilla-update.xml", $gid, $gid, 011);
|
||||
fixPerms('*', $<, $gid, 022);
|
||||
fixPerms('Bugzilla', $<, $gid, 022, 1);
|
||||
fixPerms($templatedir, $<, $gid, 022, 1);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Jacob Steenhagen <jake@bugzilla.org>
|
||||
#
|
||||
# Frédéric Buclin <LpSolit@gmail.com>
|
||||
|
||||
###############################################################################
|
||||
# Script Initialization
|
||||
|
@ -32,9 +32,11 @@ use strict;
|
|||
use lib ".";
|
||||
require "globals.pl";
|
||||
|
||||
# Check whether or not the user is logged in
|
||||
use Bugzilla::Constants;
|
||||
Bugzilla->login(LOGIN_OPTIONAL);
|
||||
use Bugzilla::Update;
|
||||
|
||||
# Check whether or not the user is logged in
|
||||
my $user = Bugzilla->login(LOGIN_OPTIONAL);
|
||||
|
||||
###############################################################################
|
||||
# Main Body Execution
|
||||
|
@ -48,10 +50,15 @@ if (Param('sslbase') ne '' and Param('ssl') ne 'never') {
|
|||
}
|
||||
|
||||
my $template = Bugzilla->template;
|
||||
my $vars = {};
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print $cgi->header();
|
||||
|
||||
if ($user->in_group('admin')) {
|
||||
$vars->{'release'} = Bugzilla::Update::get_notifications();
|
||||
}
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("index.html.tmpl")
|
||||
$template->process("index.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
|
|
@ -66,4 +66,17 @@
|
|||
padding: 1em 0;
|
||||
}
|
||||
|
||||
#new_release
|
||||
{
|
||||
border: 2px solid red;
|
||||
padding: 0.5em 1em;
|
||||
margin: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#new_release .notice
|
||||
{
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* index page (end) */
|
||||
|
|
|
@ -70,5 +70,20 @@
|
|||
|
||||
shutdownhtml => "If this field is non-empty, then $terms.Bugzilla will be completely " _
|
||||
"disabled and this text will be displayed instead of all the " _
|
||||
"$terms.Bugzilla pages." }
|
||||
"$terms.Bugzilla pages.",
|
||||
|
||||
upgrade_notification => "<p>$terms.Bugzilla can inform you when a new release is available. " _
|
||||
"The notification will appear on the $terms.Bugzilla homepage, " _
|
||||
"for administrators only.</p>" _
|
||||
"<ul><li>'development_snapshot' notifies you about the latest " _
|
||||
"release on the trunk, i.e. development snapshots.</li>" _
|
||||
"<li>'latest_stable_release' notifies you about the most recent release " _
|
||||
"available on the most recent stable branch. This branch may be " _
|
||||
"different from the branch your installation is based on.</li>" _
|
||||
"<li>'stable_branch_release' notifies you only about new releases " _
|
||||
"corresponding to the branch your installation is based on. " _
|
||||
"If you are running a release candidate, you will get " _
|
||||
"a notification for newer release candidates too.</li>" _
|
||||
"<li>'disabled' will never notify you about new releases and no " _
|
||||
"connection will be established to a remote server.</li></ul>" }
|
||||
%]
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# This template has no interface.
|
||||
# release: a hash containing data about new releases, if any.
|
||||
#%]
|
||||
|
||||
[% PROCESS global/variables.none.tmpl %]
|
||||
|
@ -56,6 +56,39 @@ function addSidebar() {
|
|||
//-->
|
||||
</script>
|
||||
|
||||
[% IF release %]
|
||||
<div id="new_release">
|
||||
[% IF release.data %]
|
||||
[% IF release.deprecated %]
|
||||
<p>[% terms.Bugzilla %] [%+ release.deprecated FILTER html %] is no longer
|
||||
supported. You are highly encouraged to upgrade in order to keep your
|
||||
system secure.</p>
|
||||
[% END %]
|
||||
|
||||
<p>A new [% terms.Bugzilla %] version ([% release.data.latest_ver FILTER html %])
|
||||
is available at
|
||||
<a href="[% release.data.url FILTER html %]">[% release.data.url FILTER html %]</a>.<br>
|
||||
Release date: [% release.data.date FILTER html %]</p>
|
||||
|
||||
<p class="notice">This message is only shown to logged in users with admin privs.
|
||||
You can configure this notification from the
|
||||
<a href="editparams.cgi?section=core#upgrade_notification">Parameters</a> page.</p>
|
||||
[% ELSIF release.error == "no_update" %]
|
||||
<p>The local XML file '[% release.xml_file FILTER html %]' cannot be updated.
|
||||
Please make sure the web server can edit this file.</p>
|
||||
[% ELSIF release.error == "no_access" %]
|
||||
<p>The local XML file '[% release.xml_file FILTER html %]' cannot be read.
|
||||
Please make sure this file exists and has the correct rights set on it.</p>
|
||||
[% ELSIF release.error == "corrupted" %]
|
||||
<p>The local XML file '[% release.xml_file FILTER html %]' has an invalid XML format.
|
||||
Please delete it and try accessing this page again.</p>
|
||||
[% ELSIF release.error == "unknown_parameter" %]
|
||||
<p>'[% Param("upgrade_notification") FILTER html %]' is not a valid notification
|
||||
parameter. Please check this parameter in the
|
||||
<a href="editparams.cgi?section=core#upgrade_notification">Parameters</a> page.</p>
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
<div id="page-index">
|
||||
<div class="intro"></div>
|
||||
|
|
Загрузка…
Ссылка в новой задаче