Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Unified Diff: install_test/chrome_installer.py

Issue 10384104: Chrome updater test framework (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome/test/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: install_test/chrome_installer.py
===================================================================
--- install_test/chrome_installer.py (revision 0)
+++ install_test/chrome_installer.py (revision 0)
@@ -0,0 +1,381 @@
+#!/usr/bin/python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import ctypes
+import urllib
+import socket
+import httplib
+import _winreg
+import tempfile
+import platform
+import urlparse
+import subprocess
+
+_PLATFORM = platform.system().lower()
+_CSIDL_COMMON_APPDATA = 28
+_CSIDL_PROGRAM_FILESX86 = 42
+
+# Import only on Windows. On other platforms it will invoke a ValueError.
+if _PLATFORM == 'windows':
+ from ctypes import wintypes, windll
+
+
+class ChromeInstaller:
+ """Provides an interface to install/uninstall Chrome."""
+
+ def __init__(self, url, build, dest, opts='', clean=True):
+ self._url = (lambda u: u if self._DoesUrlExist(u) else '')(url)
+ self._dest = dest
+ self._opts = opts
+ self._clean = clean
+ self._type = (lambda o: 'system' if o.find('system-level') != -1 else
+ 'user')(self._opts)
+ self._plat = 'win'
+ self._installer = 'mini_installer.exe'
+ self.SetBuild(build)
+ self.c_install = ChromeVersion(self._type)
+ self._c_path = self.c_install.GetChromeExePath()
+
+ def SetBuild(self, bld):
+ """Sets the build number that is to be installed."""
+ if type(bld) == str:
+ self._build = (lambda b: (all(map(lambda x: x.isdigit(), b.split('.')))
+ and len(b.split('.')) == 4) and b or '')(bld)
+ else:
+ self._build = ''
+
+ def GetBuild(self):
+ return self._build
+
+ def _DoesUrlExist(self, url):
+ """Checks if a url exists.
+
+ Args:
+ url: URL to be verified.
+
+ Returns:
+ Boolean - True if the URL exists, otherwise False.
+ """
+ parse = urlparse.urlparse(url)
+ if parse[0] == '' or parse[1] == '':
+ return False
+ try:
+ conn = httplib.HTTPConnection(parse.netloc)
+ conn.request('HEAD', parse.path)
+ res = conn.getresponse()
+ except socket.gaierror:
+ return False
+ finally:
+ conn.close()
+ # Follow both permanent (301) and temporary (302) redirects.
+ if res.status == 302 or res.status == 301:
+ return self._DoesUrlExist(res.getheader('location'))
+ return res.status == 200
+
+ def _Download(self, _file, url, dest=None):
+ """Downloads a file from the specified URL.
+
+ Args:
+ _file: Name of the file to download.
+ url: URL where the file is located.
+ dest: Where file will be downloaded(optional). Default location is CWD.
+
+ Returns:
+ Integer - zero if successful, otherwise a non-zero value.
+ """
+ f_name = (lambda d, f: os.path.join(d, f) if(d and os.path.exists(d)) else
+ os.path.join(tempfile.gettempdir(), f))(dest, _file)
+ file_url = '%s/%s' % (url, _file)
+ # Check link before downloading, urlretrieve *WILL NOT* report
+ # an error if url doesn't exist.
+ if not self._DoesUrlExist(file_url):
+ print "Could not locate the file specified."
+ return -1
+ try:
+ d = urllib.urlretrieve(file_url, f_name)
+ except IOError, err:
+ print 'CChromeInstaller._Download: ', err
+ return -1
+ if os.path.isfile(d[0]):
+ return 0
+ return 1
+
+ def _Delete(self, _path):
+ """Deletes a file or folder"""
+ try:
+ (lambda p: shutil.rmtree(p) if os.path.isdir(p) else os.remove(p))(_path)
+ return 0
+ except(OSError, IOError, TypeError), err:
+ print 'CChromeInstaller._Delete: ', err
+ return -1
+
+ def _LaunchInstaller(self, opts=''):
+ """Launches the Chrome installer using specified options.
+
+ Args:
+ opts: Any options that are to be passed to the installer.
+
+ Returns:
+ Integer - zero if successful, otherwise a non-zero value.
+ """
+ print 'Downloading installer for build %s ...' % self._build
+ build_url = '%s/%s/%s' % (self._url, self._build, self._plat)
+ if self._Download(self._installer, build_url, self._dest) != 0:
+ print 'Failed to download installer, exiting test'
+ return -1
+ print 'Launching installer...'
+ cmd = '%s %s' % (os.path.join(self._dest, self._installer), opts)
+ try:
+ return subprocess.Popen.wait(subprocess.Popen(cmd))
+ except OSError, err:
+ print 'CChromeInstaller._LaunchInstaller: ', err
+ return -2
+
+ def _RemoveDuplicates(self, args):
+ """Removes duplicates options from a list.
+
+ Args:
+ args: A list containing the options.
+
+ Returns:
+ A string without any duplicate options.
+ """
+ return ((lambda arg: arg if arg else '')
+ (' '.join(map(lambda opt: opt, list(frozenset(args.split(',')))))))
+
+ def _DoPreliminaryChecks(self, op='install'):
+ """Checks test parameters for validity and performs version checking."""
+ if _PLATFORM != 'windows':
+ print 'Unsupported platform, aborting operation...'
+ return False
+ if self._url == '':
+ print 'URL specified is not valid. Please check the URL and try again.'
+ return False
+ ver = self.c_install.GetChromeVersion()
+ c_type = self.c_install.GetInstallTypeString()
+ if op == 'install':
+ if c_type == 'system' and self._type == 'user':
+ print 'System level Chrome exists, aborting user level installation.'
+ return False
+ # Version installed is higher than or same as the one we're installing.
+ elif self._type == c_type:
+ if self._build <= ver:
+ print 'Please specify a version higher than the one installed.'
+ return False
+ elif op == 'uninstall':
+ if not ver:
+ print 'No version of Chrome found, aborting uninstall...'
+ return False
+ if self._type != c_type:
+ print ('Invalid args passed. Please specify --opts=--system-level if '
+ 'uninstalling system version of Chrome, or omit it otherwise.')
+ return False
+ return True
+
+ def InstallChrome(self):
+ """Installs specified chrome build."""
+ if not self._DoPreliminaryChecks('install'):
+ return None
+ opts = '--install --do-not-launch-chrome %s' % self._opts
+ opts = self._RemoveDuplicates(opts)
+ ret = self._LaunchInstaller(opts)
+ self._Delete(os.path.join(self._dest, self._installer))
+ if ret == 0 and os.path.exists(self._c_path):
+ print 'Installation complete...'
+ return self.c_install
+ else:
+ print 'Installation failed.'
+ return None
+
+ def UninstallChrome(self):
+ """Uninstalls Chrome."""
+ if not self._DoPreliminaryChecks('uninstall'):
+ return False
+ install_type = self.c_install.GetChromeInstallType()
+ reg_opts = self.c_install.GetUninstallArgs(install_type)
+ opts = '%s --force-uninstall %s' % (reg_opts, self._opts)
+ opts = self._RemoveDuplicates(opts)
+ if not os.path.exists(self._c_path):
+ print 'Couldn\'t find Chrome. Verify Chrome is installed and try again.'
+ return False
+ ret = self._LaunchInstaller(opts)
+ if os.path.exists(os.path.join(self._dest, self._installer)):
+ self._Delete(os.path.join(self._dest, self._installer))
+ if not os.path.exists(self._c_path):
+ print 'Chrome was successfully uninstalled...'
+ if self._clean:
+ print 'Removing registry settings...'
+ self.c_install.DeleteChromeRegEntries()
+ print 'Uninstall complete.'
+ return True
+ else:
+ print 'Uninstall failed.'
+ return False
+
+
+class ChromeVersion():
+ """Contains utility functions that provide information about installed
+
+ version of Chrome. The type of Chrome version is passed as an argument
+ to the constructor (i.e. - user or system level version).
+ """
+
+ def __init__(self, install_type):
+ self._type = install_type
+ self.HKEY_LOCAL = (r'SOFTWARE\Wow6432Node\Google\Update\ClientState'
+ '\{8A69D345-D564-463C-AFF1-A69D9E530F96}')
+ self.HKEY_USER = self.HKEY_LOCAL.replace('\\Wow6432Node', '')
+
+ def _OpenKey(self, key_type, key_name, key_access=_winreg.KEY_READ):
+ """Opens a registry key.
+
+ Args:
+ key_type: HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE.
+ key_name: Name of the key that is to be opened.
+ key_access: Type of access required (i.e. - KEY_READ or KEY_ALL_ACCESS).
+
+ Returns:
+ Handle - handle to the key if successful, otherwise zero.
+ """
+ try:
+ key = _winreg.OpenKey(key_type, key_name, 0, key_access)
+ return key
+ except(OSError, TypeError), err:
+ return 0
+
+ def _GetKeyValue(self, key, name):
+ """Gets the value of the specified key.
+
+ Args:
+ key: Handle to the key.
+ name: Name of the key.
+
+ Returns:
+ String - key value if successful, otherwise empty string.
+ """
+ try:
+ val = str(_winreg.QueryValueEx(key, name)[0])
+ return val
+ except OSError, err:
+ print 'ChromeVersion._GetKeyValue: %s' % err
+ return ''
+
+ def _GetKeyName(self, install_type, b_replace=True):
+ """Returns Chrome registry key name. """
+ if install_type == _winreg.HKEY_CURRENT_USER:
+ if b_replace:
+ return self.HKEY_USER.replace('ClientState', 'Clients')
+ else:
+ return self.HKEY_USER
+ elif install_type == _winreg.HKEY_LOCAL_MACHINE:
+ if b_replace:
+ return self.HKEY_LOCAL.replace('ClientState', 'Clients')
+ else:
+ return self.HKEY_LOCAL
+
+ def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
+ """Returns the full path of the 'Local' folder on Windows.
+
+ Args:
+ ftype: Location to look up, which could vary based on installation type.
+
+ Returns:
+ String - folder path if successful, otherwise an empty string.
+ """
+ if _PLATFORM != 'windows':
+ return ''
+ SHGetFolderPathW = windll.shell32.SHGetFolderPathW
+ SHGetFolderPathW.argtypes = [wintypes.HWND,
+ ctypes.c_int,
+ wintypes.HANDLE,
+ wintypes.DWORD,
+ wintypes.LPCWSTR]
+ path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
+ result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
+ return str(path_buf.value)
+
+ def GetInstallTypeString(self):
+ """Returns a string representing the type of Chrome installation."""
+ install_type = ({_winreg.HKEY_CURRENT_USER: 'user',
+ _winreg.HKEY_LOCAL_MACHINE: 'system'}).get(
+ self.GetChromeInstallType())
+ return install_type
+
+ def GetChromeInstallType(self):
+ """Determines Chrome installation type."""
+ c_type = None
+ key = self._OpenKey(_winreg.HKEY_CURRENT_USER,
+ self.HKEY_USER.replace('ClientState', 'Clients'))
+ if key:
+ if self._GetKeyValue(key, 'pv'):
+ c_type = _winreg.HKEY_CURRENT_USER
+ else:
+ key = self._OpenKey(_winreg.HKEY_LOCAL_MACHINE,
+ self.HKEY_USER.replace('ClientState', 'Clients'))
+ if key:
+ if self._GetKeyValue(key, 'pv'):
+ c_type = _winreg.HKEY_LOCAL_MACHINE
+ if key:
+ _winreg.CloseKey(key)
+ return c_type
+
+ def GetChromeVersion(self):
+ """Returns current Chrome version."""
+ chrome_ver = ''
+ key_type = ({'user': _winreg.HKEY_CURRENT_USER,
+ 'system' : _winreg.HKEY_LOCAL_MACHINE}).get(self._type)
+ key = self._OpenKey(key_type, self._GetKeyName(key_type))
+ if key:
+ chrome_ver = self._GetKeyValue(key, 'pv')
+ _winreg.CloseKey(key)
+ return chrome_ver
+
+ def GetUninstallArgs(self, install_type=_winreg.HKEY_CURRENT_USER):
+ """Gets chrome's uninstall arguments from the registry.
+
+ Args:
+ install_type: Type of chrome installation (user or system).
+
+ Returns:
+ String - uninstall arguments if successful, otherwise empty string.
+ """
+ c_args = ''
+ key = self._OpenKey(install_type, self._GetKeyName(install_type, False))
+ if key:
+ c_args = self._GetKeyValue(key, 'UninstallArguments')
+ _winreg.CloseKey(key)
+ return c_args
+
+ def GetChromeExePath(self):
+ """Gets Chrome's location, based on install type (i.e. user or system)."""
+ c_path = ''
+ f_id = (lambda _type: _type == 'user' and _CSIDL_COMMON_APPDATA or
+ _CSIDL_PROGRAM_FILESX86)(self._type)
+ if _PLATFORM == 'windows':
+ c_path = os.path.join(self._GetWinLocalFolder(f_id),
+ 'Google', 'Chrome',
+ 'Application', 'chrome.exe')
+ return c_path
+
+ def DeleteChromeRegEntries(self):
+ """Deletes chrome registry settings."""
+ if self._type == 'user':
+ p_key = self.HKEY_USER[: self.HKEY_USER.rfind('\\')]
+ key_name = self.HKEY_USER[self.HKEY_USER.rfind('\\') + 1 :]
+ _type = _winreg.HKEY_CURRENT_USER
+ else:
+ p_key = self.HKEY_LOCAL[: self.HKEY_LOCAL.rfind('\\')]
+ key_name = self.HKEY_LOCAL[self.HKEY_LOCAL.rfind('\\')+1:]
+ _type = _winreg.HKEY_LOCAL_MACHINE
+ key = self._OpenKey(_type, p_key, _winreg.KEY_ALL_ACCESS)
+ try:
+ _winreg.DeleteKey(key, key_name)
+ key.Close()
+ return 0
+ except _winreg.error, err:
+ print "Warning: could not delete registry settings - ", err
+ return -1
Property changes on: install_test\chrome_installer.py
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698