mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 08:35:26 +00:00
294 lines
11 KiB
Python
294 lines
11 KiB
Python
# ***** BEGIN LICENSE BLOCK *****
|
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
#
|
|
# 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 Mozilla Corporation Code.
|
|
#
|
|
# The Initial Developer of the Original Code is
|
|
# Clint Talbert.
|
|
# Portions created by the Initial Developer are Copyright (C) 2007
|
|
# the Initial Developer. All Rights Reserved.
|
|
#
|
|
# Contributor(s):
|
|
# Clint Talbert <ctalbert@mozilla.com>
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of
|
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
|
# of those above. If you wish to allow use of your version of this file only
|
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
|
# use your version of this file under the terms of the MPL, indicate your
|
|
# decision by deleting the provisions above and replace them with the notice
|
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
|
# the provisions above, a recipient may use your version of this file under
|
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
|
#
|
|
# ***** END LICENSE BLOCK *****
|
|
|
|
from optparse import OptionParser
|
|
import platform
|
|
import subprocess
|
|
import re
|
|
import time
|
|
import string
|
|
import os
|
|
import shutil
|
|
|
|
isDMG = re.compile(".*\.dmg")
|
|
isTARBZ = re.compile(".*\.tar\.bz")
|
|
isTARGZ = re.compile(".*\.tar\.gz")
|
|
isZIP = re.compile(".*\.zip")
|
|
isEXE = re.compile(".*\.exe")
|
|
_mozInstall_debug = False
|
|
|
|
def debug(s):
|
|
if _mozInstall_debug:
|
|
print "DEBUG: " + s
|
|
|
|
cygwinmatch = re.compile(".*cygwin.*", re.I)
|
|
|
|
# Copied from mozilla/testing/release/minotaur/getOSInfo.py - want this class
|
|
# to be self-sufficient without requiring another "non-standard" python lib,
|
|
# so duplicated this function from there.
|
|
def getPlatform():
|
|
# On Vista, python reports "Microsoft" and on cygwin shells it can report
|
|
# several different strings that contain the word "cygwin"
|
|
if platform.system() == "Microsoft" or cygwinmatch.search(platform.system()):
|
|
return "Windows"
|
|
else:
|
|
return platform.system()
|
|
|
|
# This code is lifted directly from the buildbot code. That we use here. I
|
|
# can't call it in buildbot without importing a trillion other things.
|
|
# Original Source: http://mxr.mozilla.org/mozilla/source/tools/buildbot/buildbot/slave/commands.py#59
|
|
def rmdirRecursive(dir):
|
|
"""This is a replacement for shutil.rmtree that works better under
|
|
windows. Thanks to Bear at the OSAF for the code."""
|
|
if not os.path.exists(dir):
|
|
return
|
|
|
|
if os.path.islink(dir):
|
|
os.remove(dir)
|
|
return
|
|
|
|
# Verify the directory is read/write/execute for the current user
|
|
os.chmod(dir, 0700)
|
|
|
|
for name in os.listdir(dir):
|
|
full_name = os.path.join(dir, name)
|
|
# on Windows, if we don't have write permission we can't remove
|
|
# the file/directory either, so turn that on
|
|
if os.name == 'nt':
|
|
if not os.access(full_name, os.W_OK):
|
|
# I think this is now redundant, but I don't have an NT
|
|
# machine to test on, so I'm going to leave it in place
|
|
# -warner
|
|
os.chmod(full_name, 0600)
|
|
|
|
if os.path.isdir(full_name):
|
|
rmdirRecursive(full_name)
|
|
else:
|
|
os.chmod(full_name, 0700)
|
|
os.remove(full_name)
|
|
os.rmdir(dir)
|
|
|
|
class MozUninstaller:
|
|
def __init__(self, **kwargs):
|
|
debug("uninstall constructor")
|
|
assert (kwargs['dest'] != "" and kwargs['dest'] != None)
|
|
assert (kwargs['productName'] != "" and kwargs['productName'] != None)
|
|
assert (kwargs['branch'] != "" and kwargs['dest'] != None)
|
|
self.dest = kwargs['dest']
|
|
self.productName = kwargs['productName']
|
|
self.branch = kwargs['branch']
|
|
|
|
# Handle the case where we haven't installed yet
|
|
if not os.path.exists(self.dest):
|
|
return
|
|
|
|
if getPlatform() == "Windows":
|
|
try:
|
|
self.doWindowsUninstall()
|
|
except:
|
|
debug("Windows Uninstall threw - not overly urgent or worrisome")
|
|
if os.path.exists(self.dest):
|
|
try:
|
|
os.rmdir(self.dest)
|
|
except OSError:
|
|
# Directories are still there - kill them all!
|
|
rmdirRecursive(self.dest)
|
|
|
|
|
|
def doWindowsUninstall(self):
|
|
debug("do windowsUninstall")
|
|
if self.branch == "1.8.0":
|
|
uninstexe = self.dest + "/uninstall/uninstall.exe"
|
|
uninstini = self.dest + "/uninstall/uninstall.ini"
|
|
debug("uninstexe: " + uninstexe)
|
|
debug("uninstini: " + uninstini)
|
|
if os.path.exists(uninstexe):
|
|
# modify uninstall.ini to run silently
|
|
debug("modifying uninstall.ini")
|
|
args = "sed -i.bak 's/Run Mode=Normal/Run Mode=Silent/' " + uninstini
|
|
proc = subprocess.Popen(args, shell=True)
|
|
# Todo handle error
|
|
proc.wait()
|
|
proc = subprocess.Popen(uninstexe, shell=True)
|
|
proc.wait()
|
|
elif self.branch == "1.8.1" or self.branch == "1.8" or self.branch == "1.9":
|
|
debug("we are in 1.8 uninstall land")
|
|
uninst = self.dest + "/uninstall/uninst.exe"
|
|
helper = self.dest + "/uninstall/helper.exe"
|
|
debug("uninst: " + uninst)
|
|
debug("helper: " + helper)
|
|
|
|
if os.path.exists(helper):
|
|
debug("helper exists")
|
|
args = helper + " /S /D=" + os.path.normpath(self.dest)
|
|
debug("running helper with args: " + args)
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
elif os.path.exists(uninst):
|
|
args = uninst + " /S /D=" + os.path.normpath(self.dest)
|
|
debug("running uninst with args: " + args)
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
else:
|
|
uninst = self.dest + "/" + self.product + "/uninstall/uninstaller.exe"
|
|
args = uninst + " /S /D=" + os.path.normpath(self.dest)
|
|
debug("running uninstaller with args: " + args)
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
time.sleep(10)
|
|
|
|
class MozInstaller:
|
|
def __init__(self, **kwargs):
|
|
debug("install constructor!")
|
|
assert (kwargs['dest'] != "" and kwargs['dest'] != None)
|
|
assert (kwargs['src'] != "" and kwargs['src'] != None)
|
|
assert (kwargs['productName'] != "" and kwargs['productName'] != None)
|
|
assert (kwargs['branch'] != "" and kwargs['branch'] != None)
|
|
self.src = kwargs['src']
|
|
self.dest = kwargs['dest']
|
|
self.productName = kwargs['productName']
|
|
self.branch = kwargs['branch']
|
|
debug("running uninstall")
|
|
uninstaller = MozUninstaller(dest = self.dest, productName = self.productName,
|
|
branch = self.branch)
|
|
|
|
if isDMG.match(self.src):
|
|
self.installDmg()
|
|
elif isTARBZ.match(self.src):
|
|
self.installTarBz()
|
|
elif isTARGZ.match(self.src):
|
|
self.installTarGz()
|
|
elif isZIP.match(self.src):
|
|
self.installZip()
|
|
elif isEXE.match(self.src):
|
|
self.installExe()
|
|
|
|
# Simple utility function to get around python's path module's inability
|
|
# to understand ~/... style paths
|
|
def normalizePath(self, path):
|
|
if path[0] == "~":
|
|
path = os.path.expanduser(path)
|
|
|
|
debug("NORMALIZE: path: " + path)
|
|
|
|
try:
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
except:
|
|
# TODO: Better catch and error message
|
|
print "Error creating destination directory"
|
|
return path
|
|
|
|
def installDmg(self):
|
|
# Ensure our destination directory exists
|
|
self.dest = self.normalizePath(self.dest)
|
|
|
|
args = "sh installdmg.sh " + self.src + " " + self.dest
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
# TODO: throw stderr
|
|
|
|
def installTarBz(self):
|
|
# Ensure our destination directory exists
|
|
self.dest = self.normalizePath(self.dest)
|
|
self.unTar("-jxvf")
|
|
|
|
def installTarGz(self):
|
|
# Ensure our destination directory exists
|
|
self.dest = self.normalizePath(self.dest)
|
|
self.unTar("-zxvf")
|
|
|
|
def unTar(self, tarArgs):
|
|
args = "tar " + tarArgs + " " + self.src + " -C " + self.dest
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
#TODO: throw stderr
|
|
|
|
def installZip(self):
|
|
self.dest = self.normalizePath(self.dest)
|
|
args = "unzip -o -d " + self.dest + " " + self.src
|
|
proc = subprocess.Popen(args, shell=True)
|
|
proc.wait()
|
|
# TODO: throw stderr
|
|
|
|
def installExe(self):
|
|
debug("running installEXE")
|
|
args = self.src + " "
|
|
if self.branch == "1.8.0":
|
|
args += "-ms -hideBanner -dd " + self.dest
|
|
else:
|
|
debug("running install exe for 1.8.1")
|
|
args += "/S /D=" + os.path.normpath(self.dest)
|
|
# Do we need a shell=True here?
|
|
proc = subprocess.Popen(args)
|
|
proc.wait()
|
|
# TODO: throw stderr
|
|
|
|
# Enable it to be called from the command line with the options
|
|
if __name__ == "__main__":
|
|
parser = OptionParser()
|
|
parser.add_option("-s", "--Source", dest="src",
|
|
help="Installation Source File (whatever was downloaded) -\
|
|
accepts Zip, Exe, Tar.Bz, Tar.Gz, and DMG",
|
|
metavar="SRC_FILE")
|
|
parser.add_option("-d", "--Destination", dest="dest",
|
|
help="Directory to install the build into", metavar="DEST")
|
|
parser.add_option("-b", "--Branch", dest="branch",
|
|
help="Branch the build is from must be one of: 1.8.0|1.8|\
|
|
1.9", metavar="BRANCH")
|
|
parser.add_option("-p", "--Product", dest="product",
|
|
help="Product name - optional should be all lowercase if\
|
|
specified: firefox, thunderbird, etc",
|
|
metavar="PRODUCT")
|
|
parser.add_option("-o", "--Operation", dest="op",
|
|
help="The operation you would like the script to perform.\
|
|
Should be either install (i) or uninstall (u) or delete\
|
|
(d) to recursively delete the directory specified in dest",
|
|
metavar="OP")
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
# Run it
|
|
if string.upper(options.op) == "INSTALL" or string.upper(options.op) == "I":
|
|
installer = MozInstaller(src = options.src, dest = options.dest,
|
|
branch = options.branch, productName = options.product)
|
|
elif string.upper(options.op) == "UNINSTALL" or string.upper(options.op) == "U":
|
|
uninstaller = MozUninstaller(dest = options.dest, branch = options.branch,
|
|
productName = options.product)
|
|
elif string.upper(options.op) == "DELETE" or string.upper(options.op) == "D":
|
|
rmdirRecursive(options.dest)
|