mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 12:15:51 +00:00
620 lines
17 KiB
Perl
620 lines
17 KiB
Perl
#!/usr/bin/perl -w
|
|
# -*- 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 Testopia System.
|
|
#
|
|
# The Initial Developer of the Original Code is Maciej Maczynski.
|
|
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
|
# Maciej Maczynski. All Rights Reserved.
|
|
#
|
|
# Contributor(s): Maciej Maczynski <macmac@xdsnet.pl>
|
|
# Ed Fuentetaja <efuentetaja@acm.org>
|
|
|
|
use DBI;
|
|
use File::Copy;
|
|
|
|
require Bugzilla;
|
|
use Bugzilla::Constants;
|
|
|
|
my $VERSION = "1.0-beta";
|
|
|
|
#check that we are on the Bugzilla's directory:
|
|
|
|
if (! -e "testopia") {
|
|
# I don't know where the heck I am
|
|
DieWithStyle("Please unpack Testopia's distribution file and run this script from within Bugzilla's directory.\n".
|
|
"Can't continue.\n");
|
|
}
|
|
|
|
if (! -e "localconfig") {
|
|
DieWithStyle("Can't find file: localconfig\nBugzilla is not installed in this directory.\n".
|
|
"Can't continue.\n");
|
|
}
|
|
|
|
print "Now installing Testopia ...\n\n";
|
|
|
|
do 'localconfig';
|
|
|
|
my $rollbackPatchOnFail = 0;
|
|
my $patchSuccessFile = "testopia/tr_patch_successful";
|
|
my @files = ();
|
|
|
|
my $patchFile = $ARGV[0];
|
|
|
|
if ($patchFile && $patchFile eq "-nopatch") {
|
|
#skip patching
|
|
print "Skip patching Bugzilla's files.\n";
|
|
} else {
|
|
doPatch($patchFile);
|
|
}
|
|
|
|
print "\nSetting file permissions ...\n";
|
|
SetupPermissions();
|
|
print "Done.\n\n";
|
|
|
|
print "Checking Testopia database ...\n";
|
|
my ($dbh, $my_db_base, $my_db_host, $my_db_port, $my_db_name, $my_db_user, $my_db_sock) = DBConnect();
|
|
print " Make : $my_db_base\n";
|
|
print " Host : $my_db_host\n";
|
|
print " Port : $my_db_port\n";
|
|
print " Name : $my_db_name\n";
|
|
print " User : $my_db_user\n";
|
|
print " Socket: $my_db_sock\n";
|
|
print "\n";
|
|
UpdateDB($dbh);
|
|
print "Done.\n\n";
|
|
|
|
print "Adding Testopia groups ...\n";
|
|
# Identify admin group.
|
|
my $adminid = GetAdminGroup($dbh);
|
|
#Create groups if needed and grant permissions to the admin group over them
|
|
my $groupid;
|
|
$groupid = tr_AddGroup($dbh, 'managetestplans', 'Can create, destroy, run and edit test plans.', $adminid);
|
|
tr_AssignAdminGrants($dbh, $groupid, $adminid);
|
|
$groupid = tr_AddGroup($dbh, 'edittestcases', 'Can add, delete and edit test cases.', $adminid);
|
|
tr_AssignAdminGrants($dbh, $groupid, $adminid);
|
|
$groupid = tr_AddGroup($dbh, 'runtests', 'Can add, delete and edit test runs.', $adminid);
|
|
tr_AssignAdminGrants($dbh, $groupid, $adminid);
|
|
|
|
print "Done.\n\n";
|
|
|
|
DBDisconnect($dbh);
|
|
|
|
#print "Copying Testopia templates ...\n";
|
|
#CopyTemplates('testopia');
|
|
#CopyTemplates('hook');
|
|
#print "Done.\n\n";
|
|
|
|
print "Cleaning up Testopia cache ...\n";
|
|
unlink "data/plancache";
|
|
print "Done.\n\n";
|
|
|
|
print "Running checksetup.pl ...\n";
|
|
`perl checksetup.pl`;
|
|
print "Done.\n\n";
|
|
|
|
#now recover permissions over this script:
|
|
chmod(0750, "tr_install.pl");
|
|
|
|
print "Testopia installed successfully!\n";
|
|
|
|
print "\n";
|
|
print "Please follow now the 'Users' link at the bottom of your Bugzilla's home page to assign users to groups 'Edittestcases' and 'Managetestplans'.\n";
|
|
print "\n";
|
|
|
|
1;
|
|
|
|
|
|
###############################################################################
|
|
|
|
sub CopyTemplates {
|
|
|
|
my ($d) = @_;
|
|
|
|
my $src = "testopia/template/en/default/$d";
|
|
my $dst = "template/en/default/$d";
|
|
|
|
_copyRec($src, $dst);
|
|
}
|
|
|
|
sub _copyRec {
|
|
|
|
my ($src, $dst) = (@_);
|
|
|
|
opendir DIRH, $src;
|
|
my @files = grep( $_ ne "." && $_ ne "..", readdir(DIRH));
|
|
closedir DIRH;
|
|
|
|
mkdir $dst;
|
|
foreach my $f (@files) {
|
|
if (-d "$src/$f") {
|
|
# A directory
|
|
_copyRec("$src/$f", "$dst/$f");
|
|
} else {
|
|
copy("$src/$f", "$dst/$f");
|
|
}
|
|
}
|
|
}
|
|
|
|
sub doPatch {
|
|
|
|
my ($fPatch) = @_;
|
|
|
|
if (-e $patchSuccessFile) {
|
|
|
|
#TODO: check the version run, in case we are upgrading
|
|
#since version 0.6.2 is the first version using this system
|
|
#this won't be needed until next version (0.6.3 ?) comes along
|
|
|
|
print "Patch already run successfully. Skipping.\n";
|
|
return 1;
|
|
}
|
|
|
|
print "Patching Bugzilla's files ...\n";
|
|
|
|
if ($fPatch) {
|
|
# check that the patch file exists:
|
|
if (!-e $fPatch) {
|
|
DieWithStyle("Cannot find patch file: $fPatch\n".
|
|
"Please, double-check the patch's file name and try again.");
|
|
}
|
|
|
|
print "\nUsing patch file: $fPatch\n\n";
|
|
|
|
} else {
|
|
# Guess the patch file to use:
|
|
print "\nNo patch file especified, trying to determine the right one to use ...\n\n";
|
|
|
|
print "Bugzilla version ".$Bugzilla::Config::VERSION." detected.\n";
|
|
|
|
# This piece of code needs to be modified when a new patch file is added to the distribution:
|
|
|
|
if ($Bugzilla::Config::VERSION =~ /^2\.18.*/) {
|
|
# version 2.18.* detected
|
|
$fPatch = "patch-2.18";
|
|
} elsif ($Bugzilla::Config::VERSION =~ /^2\.19\.2$/) {
|
|
# version 2.19.2 detected
|
|
$fPatch = "patch-2.19.2";
|
|
} elsif ($Bugzilla::Config::VERSION =~ /^2\.19\.3$/) {
|
|
# version 2.19.3 detected
|
|
$fPatch = "patch-2.19.3";
|
|
} elsif ($Bugzilla::Config::VERSION =~ /^2\.20.*/) {
|
|
# version 2.20.* detected
|
|
$fPatch = "patch-2.20";
|
|
} else {
|
|
# no suitable version available
|
|
DieWithStyle("No suitable patch detected for your Bugzilla. Patch cannot continue.\n".
|
|
"Still, there is a chance that a manual patch might work on your installation. Please, check out Testopia's installation manual for details.");
|
|
}
|
|
|
|
print "Patch file chosen: $fPatch\n\n";
|
|
|
|
if (isWindows()) {
|
|
$fPatch = "testopia\\".$fPatch;
|
|
} else {
|
|
$fPatch = "testopia/".$fPatch;
|
|
}
|
|
}
|
|
|
|
|
|
# Read the files involved in the patch and put them in @files
|
|
readPatchFiles($fPatch, \@files);
|
|
|
|
# Now, let's go ahead and run the patch command:
|
|
|
|
print "Now patching ...\n\n";
|
|
|
|
my $patchPath = "patch";
|
|
if (isWindows()) {
|
|
$patchPath = "testopia\\tools\\patch.exe";
|
|
}
|
|
|
|
my $output;
|
|
|
|
# Check out if patch is installed:
|
|
$output = `$patchPath -v` || DieWithStyle("Patch failed. Is 'patch' installed and in your path?");
|
|
|
|
# Patch doesn't really run yet: --dry-run
|
|
# print "$patchPath -s --dry-run -bp 1 -i $fPatch 2>&1 \n";
|
|
# exit;
|
|
|
|
$output = `$patchPath -s -l --dry-run -bp 2 -i $fPatch 2>&1`;
|
|
|
|
# If the output is empty, everything was perfect (the -s argument)
|
|
chomp $output;
|
|
if ($output) {
|
|
|
|
# Nop... the patch didn't apply correctly:
|
|
|
|
# Print out the output:
|
|
print $output;
|
|
|
|
DieWithStyle ("\n*** Patching of Bugzilla's files failed. None of your files has been modified.\n".
|
|
"\n".
|
|
"Some possible reasons:\n".
|
|
"\n".
|
|
"- Your Bugzilla installation has been modified from the original.\n".
|
|
"> Please scroll up and see if the patch command output you can see above gives you any clue. Consult Testopia's installation manual and get ready for some manual patching.\n".
|
|
"\n".
|
|
"- The patch file used was the wrong version.\n".
|
|
"> If you didn't especify the patch file to use, maybe this installation script picked up the wrong one. ".
|
|
"In this case, please, check out in the testopia directory the list of available patch files (files named as patch*) and run the install script especifying the file to use, according to the Bugzilla's version you are using. ".
|
|
"For instance, if you are using Bugzilla version 2.19.2, this is the command line you should use:\n".
|
|
" tr_install.pl testopia/patch-2.19.2\n".
|
|
"> If you did in fact especify a patch file on the command line, please, double-check your Bugzilla version and the patch file you used and try again.\n".
|
|
"\n".
|
|
"- Testopia is not prepared to work with this particular version of Bugzilla.\n".
|
|
"> Please, check the documentation. Verify that this version of Bugzilla is supported.\n".
|
|
"\n".
|
|
"If you still have problems, please, check out Testopia's installation manual again and, if nothing helps, report the problem to Testopia sourceforge forum at http://sourceforge.net/projects/testopia.");
|
|
|
|
}
|
|
|
|
$rollbackPatchOnFail = 1;
|
|
|
|
#Now let's really run the patch:
|
|
$output = `$patchPath -s -l -z .orig -bp 2 -i $fPatch`;
|
|
|
|
# If the output is empty, everything was perfect (the -s argument)
|
|
chomp $output;
|
|
if ($output) {
|
|
|
|
# Nop... the patch didn't apply correctly:
|
|
|
|
# Print out the output:
|
|
print $output;
|
|
|
|
DieWithStyle ("\n*** Unexpected condition. Patch failed, but I was pretty sure it should have worked.\n".
|
|
"Try to repeat the installation.\n");
|
|
}
|
|
|
|
$rollbackPatchOnFail = 0;
|
|
|
|
print "\nDone.\n";
|
|
|
|
restorePermissions();
|
|
|
|
open(MYOUTPUTFILE, ">$patchSuccessFile") or DieWithStyle("Couldn't write file: $patchSuccessFile");
|
|
print MYOUTPUTFILE $VERSION;
|
|
close(MYOUTPUTFILE);
|
|
|
|
print "\n";
|
|
print "Congratulations, patch worked flawless!\n";
|
|
print "\n";
|
|
print "A backup copy of the modified files has been saved with the .orig sufix.\n";
|
|
|
|
1;
|
|
}
|
|
|
|
sub isWindows {
|
|
|
|
return ($^O eq "MSWin32" || $^O eq "cygwin");
|
|
}
|
|
|
|
sub SetupPermissions {
|
|
|
|
if (isWindows()) {
|
|
SetupPermissions_windows();
|
|
} else {
|
|
SetupPermissions_unix();
|
|
}
|
|
}
|
|
|
|
sub SetupPermissions_windows {
|
|
|
|
print "Running on Windows or Cygwin... skipping permissions...\n";
|
|
}
|
|
|
|
sub SetupPermissions_unix {
|
|
`chmod 750 tr_*.cgi`;
|
|
`chmod 640 tr_*.pl`;
|
|
`chmod 750 tr_install.pl`;
|
|
`chmod 750 testopia`;
|
|
`chmod 750 testopia/tr_*`;
|
|
`chmod -R 750 testopia/doc`;
|
|
`chmod -R 750 testopia/img`;
|
|
`chmod -R 750 testopia/css`;
|
|
`chmod -R 750 testopia/js`;
|
|
`chmod -R 750 testopia/dojo-ajax`;
|
|
`chmod -R 750 testopia/scripts`;
|
|
`chmod 770 testopia/temp`;
|
|
if (defined $::webservergroup && ($::webservergroup ne '')) {
|
|
print " Webserver group: $::webservergroup\n";
|
|
`chown :$::webservergroup tr_*`;
|
|
`chown :$::webservergroup testopia`;
|
|
`chown :$::webservergroup testopia/tr_*`;
|
|
`chown -R :$::webservergroup testopia/doc`;
|
|
`chown -R :$::webservergroup testopia/img`;
|
|
`chown -R :$::webservergroup testopia/css`;
|
|
`chown -R :$::webservergroup testopia/js`;
|
|
`chown -R :$::webservergroup testopia/dojo-ajax`;
|
|
`chown -R :$::webservergroup testopia/scripts`;
|
|
`chown :$::webservergroup testopia/temp`;
|
|
}
|
|
}
|
|
|
|
sub UpdateDB {
|
|
|
|
my ($dbh) = (@_);
|
|
|
|
my $testRunnerDBPresent = 0;
|
|
|
|
my $qh;
|
|
|
|
$qh = $dbh->prepare("SHOW TABLES LIKE 'test_cases'");
|
|
$qh->execute;
|
|
if ($qh->rows) {
|
|
#assume that the BTR 0.4.5 db was created successfuly
|
|
$testRunnerDBPresent = 1;
|
|
}
|
|
$qh->finish;
|
|
|
|
if ($testRunnerDBPresent) {
|
|
print " Testopia database already present.\n";
|
|
|
|
|
|
} else {
|
|
print " No Testopia database was detected. Need to create it ...\n";
|
|
|
|
#Run the create db script:
|
|
RunSQLScript('testopia/testopia.create.sql');
|
|
print " Done.\n";
|
|
}
|
|
}
|
|
|
|
# Copied from checksetup.pl
|
|
#
|
|
## This subroutine checks if a group exist. If not, it will be automatically
|
|
## created with the next available groupid
|
|
##
|
|
#
|
|
|
|
sub tr_AddGroup {
|
|
|
|
my ($dbh, $name, $desc) = @_;
|
|
|
|
my ($id) = GroupDoesExist($dbh, $name);
|
|
|
|
return $id if $id;
|
|
|
|
print "Adding group $name ...\n";
|
|
my $sth = $dbh->prepare('INSERT INTO groups
|
|
(name, description, userregexp, isbuggroup)
|
|
VALUES (?, ?, ?, ?)');
|
|
$sth->execute($name, $desc, '', 0);
|
|
$sth = $dbh->prepare("SELECT last_insert_id()");
|
|
$sth->execute();
|
|
($id) = $sth->fetchrow_array();
|
|
|
|
return $id;
|
|
}
|
|
|
|
sub GetAdminGroup {
|
|
|
|
my ($dbh) = @_;
|
|
|
|
my $sth = $dbh->prepare("SELECT id FROM groups WHERE name = 'admin'");
|
|
$sth->execute();
|
|
my ($adminid) = $sth->fetchrow_array();
|
|
|
|
return $adminid;
|
|
}
|
|
|
|
sub tr_AssignAdminGrants {
|
|
|
|
my ($dbh, $id, $adminid) = @_;
|
|
|
|
#clean up first:
|
|
$dbh->do("DELETE FROM group_group_map ".
|
|
"WHERE member_id=$adminid AND grantor_id=$id");
|
|
|
|
#Assign privileges to the admin group over this group:
|
|
|
|
my $blessColumn;
|
|
my $group_membership;
|
|
my $group_bless;
|
|
if ($Bugzilla::Config::VERSION =~ /^2\.18.*/) {
|
|
# version 2.18.* detected
|
|
$blessColumn = 'isbless';
|
|
$group_membership = 0;
|
|
$group_bless = 1;
|
|
} else {
|
|
$blessColumn = 'grant_type';
|
|
$group_membership = GROUP_MEMBERSHIP;
|
|
$group_bless = GROUP_BLESS;
|
|
}
|
|
|
|
# Admins can bless.
|
|
$dbh->do("INSERT INTO group_group_map ".
|
|
"(member_id, grantor_id, $blessColumn) ".
|
|
"VALUES ($adminid, $id," . $group_bless . ")");
|
|
# Admins can see.
|
|
#$dbh->do("INSERT INTO group_group_map
|
|
# (member_id, grantor_id, grant_type)
|
|
# VALUES ($adminid, $last," . GROUP_VISIBLE . ")");
|
|
# Admins are initially members.
|
|
$dbh->do("INSERT INTO group_group_map ".
|
|
"(member_id, grantor_id, $blessColumn) ".
|
|
"VALUES ($adminid, $id," . $group_membership . ")");
|
|
}
|
|
|
|
sub GroupDoesExist {
|
|
|
|
my ($dbh, $name) = @_;
|
|
my $sth = $dbh->prepare("SELECT id FROM groups WHERE name='$name'");
|
|
$sth->execute;
|
|
my $id = 0;
|
|
if ($sth->rows) {
|
|
($id) = $sth->fetchrow_array();
|
|
}
|
|
return $id;
|
|
}
|
|
|
|
sub GetDBConnectionInfo {
|
|
|
|
my $my_db_base = 'mysql';
|
|
# code taken from checksetup.pl:
|
|
my $my_db_host = ${*{$main::{'db_host'}}{SCALAR}};
|
|
my $my_db_port = ${*{$main::{'db_port'}}{SCALAR}};
|
|
my $my_db_name = ${*{$main::{'db_name'}}{SCALAR}};
|
|
my $my_db_user = ${*{$main::{'db_user'}}{SCALAR}};
|
|
my $my_db_pass = ${*{$main::{'db_pass'}}{SCALAR}};
|
|
my $my_db_sock = '';
|
|
if (defined $main::{'db_sock'}) {
|
|
$my_db_sock = ${*{$main::{'db_sock'}}{SCALAR}};
|
|
}
|
|
|
|
($my_db_base, $my_db_host, $my_db_port, $my_db_name,
|
|
$my_db_user, $my_db_pass, $my_db_sock);
|
|
}
|
|
|
|
sub DBConnect {
|
|
|
|
my ($my_db_base, $my_db_host, $my_db_port, $my_db_name,
|
|
$my_db_user, $my_db_pass, $my_db_sock) = GetDBConnectionInfo();
|
|
|
|
my $dsn = "DBI:$my_db_base:$my_db_name:host=$my_db_host:port=$my_db_port";
|
|
if ($my_db_sock ne '') {
|
|
$dsn .= ";mysql_socket=$my_db_sock";
|
|
}
|
|
my $dbh = DBI->connect($dsn, $my_db_user, $my_db_pass)
|
|
|| DieWithStyle("Can't connect to the $my_db_base database. Is the database " .
|
|
"installed and up and running? Do you have the correct username " .
|
|
"and password selected in\nlocalconfig?");
|
|
($dbh, $my_db_base, $my_db_host, $my_db_port, $my_db_name,
|
|
$my_db_user, $my_db_sock);
|
|
}
|
|
|
|
sub DBDisconnect {
|
|
|
|
my ($dbh) = (@_);
|
|
$dbh->disconnect if $dbh;
|
|
}
|
|
|
|
sub RunSQLScript {
|
|
|
|
my ($script) = (@_);
|
|
|
|
my ($my_db_base, $my_db_host, $my_db_port, $my_db_name,
|
|
$my_db_user, $my_db_pass, $my_db_sock) = GetDBConnectionInfo();
|
|
|
|
my $cmdline = "mysql -h$my_db_host -P$my_db_port -u $my_db_user $my_db_name -p$my_db_pass";
|
|
if ($my_db_sock ne '') {
|
|
$cmdline.= " -S$my_db_sock";
|
|
}
|
|
$cmdline.= ' < '.$script;
|
|
|
|
my $output;
|
|
|
|
#Check out that mysql is installed and can be reached:
|
|
$output = `mysql -V` || DieWithStyle("MySql command failed. Is 'mysql' installed and in your path?");
|
|
|
|
$output = `$cmdline 2>&1`;
|
|
print $output;
|
|
# If the output is empty, everything was perfect
|
|
chomp $output;
|
|
if ($output) {
|
|
DieWithStyle("Could not create Testopia's tables. See previous errors.");
|
|
} else {
|
|
print " Testopia's tables created successfully.\n";
|
|
}
|
|
}
|
|
|
|
sub DieWithStyle {
|
|
|
|
my($message) = @_;
|
|
|
|
print "\n$message\n";
|
|
|
|
if ($rollbackPatchOnFail) {
|
|
rollbackPatch();
|
|
}
|
|
|
|
die "\nInstall failed. See details above.\n";
|
|
}
|
|
|
|
sub readPatchFiles {
|
|
|
|
my($path, $f) = (@_);
|
|
|
|
open(MYINPUTFILE, "<$path") or DieWithStyle("Couldn't find file: $path");
|
|
while (<MYINPUTFILE>) {
|
|
my $line = $_;
|
|
if($line =~ /^diff -[\w]* \.\/([^ ]*) .*$/) {
|
|
push @$f, $1;
|
|
}
|
|
}
|
|
close(MYINPUTFILE);
|
|
}
|
|
|
|
sub rollbackPatch {
|
|
|
|
# Recoved files from the .orig copies made by patch:
|
|
|
|
print "\n";
|
|
print "Restoring original files ...\n";
|
|
foreach my $file (@files) {
|
|
if (-e $file.".orig") {
|
|
rename($file.".orig", $file);
|
|
} else {
|
|
print " Couldnt't restore file: $file because $file.orig doesn't exit!.\n";
|
|
}
|
|
}
|
|
print "Done.\n";
|
|
}
|
|
|
|
sub restorePermissions {
|
|
|
|
# Restore permissions from the .orig files:
|
|
|
|
print "\n";
|
|
print "Recovering original permissions ...\n";
|
|
foreach my $file (@files) {
|
|
perm_cp($file.".orig", $file);
|
|
}
|
|
print "Done.\n";
|
|
}
|
|
|
|
######################################
|
|
# perm_cp lifted from Ben Okopnik's
|
|
# http://www.linuxgazette.com/issue87/misc/tips/cpmod.pl.txt
|
|
|
|
sub perm_cp {
|
|
|
|
my $perms = perm_get($_[0]);
|
|
perm_set($_[1], $perms);
|
|
}
|
|
|
|
sub perm_get {
|
|
|
|
my($filename) = @_;
|
|
|
|
my @stats = (stat $filename)[2,4,5] or
|
|
DieWithStyle("Cannot stat $filename ($!)");
|
|
|
|
return \@stats;
|
|
}
|
|
|
|
sub perm_set {
|
|
|
|
my($filename, $perms) = @_;
|
|
|
|
chown($perms->[1], $perms->[2], $filename) or
|
|
DieWithStyle("Cannot chown $filename ($!)");
|
|
|
|
chmod($perms->[0] & 07777, $filename) or
|
|
DieWithStyle("Cannot chmod $filename ($!)");
|
|
}
|
|
|
|
######################################
|