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

Side by Side 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, 5 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 unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Provides an interface for installing Chrome."""
7
8 import _winreg
9 import ctypes
10 import httplib
11 import logging
12 import os
13 import platform
14 import shutil
15 import socket
16 import subprocess
17 import tempfile
18 import urllib
19
20
21 _CSIDL_COMMON_APPDATA = 0x1C
22 _CSIDL_PROGRAM_FILESX86 = 0x2A
23 _PLATFORM = platform.system().lower()
24
25 # Import only on Windows. On other platforms it will invoke a ValueError.
26 if _PLATFORM == 'windows':
27 from ctypes import wintypes, windll
28
29
30 class InstallationType:
31 """Defines the Chrome installation types."""
32 SYSTEM = 0
33 USER = 1
34
35
36 def _RemoveDuplicates(args):
37 """Removes duplicates options from a list.
38
39 Args:
40 args: A list containing the options.
41
42 Returns:
43 A string without any duplicate options.
44 """
45 return ((lambda arg: arg if arg else '')
46 (' '.join(map(lambda opt: opt, list(frozenset(args.split(',')))))))
47
48
49 def Install(installer_path, chrome_type, build, options='', clean=True):
50 """Installs the specified Chrome build."""
51 def DoPreliminaryChecks(chrome_install):
52 """Validates the test parameters and Chrome version."""
53 assert(_PLATFORM == 'windows' and os.path.isfile(installer_path))
54 # Chrome installation type specified by the user.
55 install_type = ('system-level' in options and InstallationType.SYSTEM
56 or InstallationType.USER)
57 cur_build = chrome_install.GetChromeVersion()
58 # Chrome already installed, make sure new build can be installed over it.
59 if cur_build:
60 current_type = chrome_install.GetChromeInstallationType()
61 if(current_type == InstallationType.SYSTEM and install_type ==
62 InstallationType.USER):
63 raise RuntimeError('System level Chrome exists, aborting user level '
64 'installation.')
65 # Installing a build that's older than the currently installed build.
66 elif current_type == install_type:
67 if cur_build >= build:
68 raise RuntimeError('Please specify a newer version of Chrome.')
69
70 chrome_install = Installation(chrome_type)
71 DoPreliminaryChecks(chrome_install)
72 options += ' --install --do-not-launch-chrome'
73 options = _RemoveDuplicates(options)
74 logging.log(logging.INFO, 'Launching Chrome installer...')
75 cmd = '%s %s' % (installer_path, options)
76 ret = subprocess.Popen(cmd, shell=True).wait()
77 if ret == 0:
78 logging.log(logging.INFO, 'Installation complete.')
79 return chrome_install
80 logging.log(logging.ERROR, 'Installation failed.')
81 return None
82
83
84 class Installation(object):
85 """Provides pertinent information about the installed Chrome version.
86
87 The type of Chrome version must be passed as an argument to the constructor,
88 (i.e. - user or system level).
89 """
90
91 HKEY_LOCAL = (r'SOFTWARE\Wow6432Node\Google\Update\ClientState'
92 '\{8A69D345-D564-463C-AFF1-A69D9E530F96}')
93 HKEY_USER = HKEY_LOCAL.replace('\\Wow6432Node', '')
94
95 def __init__(self, install_type):
96 assert(install_type == InstallationType.SYSTEM or
97 install_type == InstallationType.USER)
98 self._type = install_type
99 self._key_type = self._GetKeyType(self._type)
100
101 def _OpenKey(self, key_type, key_name, key_access=_winreg.KEY_READ):
102 """Opens a registry key and returns the key handle.
103
104 Args:
105 key_type: The type of key HKLM or HKCU.
106 key_name: Name of the key.
107 key_access: Type of access required. Be default its read only.
108
109 Returns:
110 Key handle if successful, otherwise None.
111 """
112 try:
113 key = _winreg.OpenKey(key_type, key_name, 0, key_access)
114 return key
115 except _winreg.error:
116 return None
117
118 def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
119 """Returns full path of the 'Local' folder on Windows.
120
121 Args:
122 ftype: Location to look up, which could vary based on installation type.
123
124 Returns:
125 A String representing the folder path if successful, otherwise an empty
126 string.
127 """
128 if _PLATFORM != 'windows':
129 return ''
130 SHGetFolderPathW = windll.shell32.SHGetFolderPathW
131 SHGetFolderPathW.argtypes = [wintypes.HWND,
132 ctypes.c_int,
133 wintypes.HANDLE,
134 wintypes.DWORD,
135 wintypes.LPCWSTR]
136 path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
137 result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
138 return str(path_buf.value)
139
140 def _GetKeyType(self, install_type):
141 """Determines the registry key to use based on installation type."""
142 if install_type == InstallationType.SYSTEM:
143 return _winreg.HKEY_LOCAL_MACHINE
144 elif install_type == InstallationType.USER:
145 return _winreg.HKEY_CURRENT_USER
146
147 def _GetKeyName(self, install_type, replace=True):
148 """Returns Chrome's registry key name based on installation type."""
149 name = (install_type == InstallationType.SYSTEM and self.HKEY_LOCAL or
150 self.HKEY_USER)
151 return (replace and name.replace('ClientState', 'Clients') or name)
152
153 def _DeleteChromeRegEntries(self):
154 """Deletes chrome registry settings."""
155 if self._type == InstallationType.USER:
156 p_key = self.HKEY_USER[: self.HKEY_USER.rfind('\\')]
157 key_name = self.HKEY_USER[self.HKEY_USER.rfind('\\') + 1 :]
158 _type = _winreg.HKEY_CURRENT_USER
159 elif self._type == InstallationType.SYSTEM:
160 p_key = self.HKEY_LOCAL[: self.HKEY_LOCAL.rfind('\\')]
161 key_name = self.HKEY_LOCAL[self.HKEY_LOCAL.rfind('\\') + 1 :]
162 _type = _winreg.HKEY_LOCAL_MACHINE
163 try:
164 key = self._OpenKey(_type, p_key, _winreg.KEY_ALL_ACCESS)
165 _winreg.DeleteKey(key, key_name)
166 key.Close()
167 return 0
168 except _winreg.error, err:
169 logging.log(logging.ERROR, 'Could not delete registry entries: %s' % err)
170 return -1
171
172 def _GetValueFromRegistry(self, reg_type, key, subkey):
173 """Gets value of the specified subkey from the registry.
174
175 Args:
176 reg_type: Type of key to use HKLM or HKCU.
177 key: Name of the key.
178 subkey: Name of the subkey whose value will be returned.
179
180 Returns:
181 A string representing the subkey value if successful, otherwise None.
182 """
183 hkey = self._OpenKey(reg_type, key)
184 if hkey:
185 try:
186 value = str(_winreg.QueryValueEx(hkey, subkey)[0])
187 except _winreg.error:
188 value = None
189 _winreg.CloseKey(hkey)
190 return value
191 return None
192
193 def _GetUninstallString(self):
194 """Returns Chrome uninstall string from the registry."""
195 key_name = self._GetKeyName(self._type, False)
196 return self._GetValueFromRegistry(self._key_type, key_name,
197 'UninstallString')
198
199 def _GetUninstallArguments(self):
200 """Returns Chrome uninstall arguments from the registry."""
201 key_name = self._GetKeyName(self._type, False)
202 return self._GetValueFromRegistry(self._key_type, key_name,
203 'UninstallArguments')
204
205 def GetChromeVersion(self):
206 """Returns the installed version of Chrome."""
207 key_name = self._GetKeyName(self._type, True)
208 return self._GetValueFromRegistry(self._key_type, key_name, 'pv')
209
210 def _LaunchInstaller(self, installer_path, options):
211 """Launches the Chrome installer.
212
213 Args:
214 installer_path: Path where the installer is located.
215 options: Any additional options to be used for installation.
216 """
217 cmd = '%s %s' % (installer_path, options)
218 try:
219 subprocess.Popen(cmd, shell=True).wait()
220 except OSError, err:
221 raise err
222
223 def _Delete(self, _path):
224 """Deletes a file or folder."""
225 try:
226 (lambda p: shutil.rmtree(p) if os.path.isdir(p) else os.remove(p))(_path)
227 return 0
228 except(OSError, IOError, TypeError), err:
229 return -1
230
231 def GetChromeExePath(self):
232 """Returns Chrome binary location based on installation type."""
233 chrome_path = ''
234 if self._type == InstallationType.USER:
235 folder_id = _CSIDL_COMMON_APPDATA
236 elif self._type == InstallationType.SYSTEM:
237 folder_id = _CSIDL_PROGRAM_FILESX86
238 if _PLATFORM == 'windows':
239 chrome_path = os.path.join(self._GetWinLocalFolder(folder_id), 'Google',
240 'Chrome', 'Application', 'chrome.exe')
241 return chrome_path
242
243 def GetChromeInstallationType(self):
244 """Determines Chrome installation type."""
245 reg_type = _winreg.HKEY_CURRENT_USER
246 key_name = self.HKEY_USER.replace('ClientState', 'Clients')
247 key = self._OpenKey(reg_type, key_name)
248 if not key:
249 reg_type = _winreg.HKEY_LOCAL_MACHINE
250 key_name = self.HKEY_LOCAL.replace('ClientState', 'Clients')
251 key = self._OpenKey(reg_type, key_name)
252 if not key:
253 return None
254 version = self._GetValueFromRegistry(reg_type, key_name, 'pv')
255 key.Close()
256 if version:
257 return (reg_type == _winreg.HKEY_CURRENT_USER and
258 InstallationType.USER or InstallationType.SYSTEM)
259 return None
260
261 def UninstallChrome(self):
262 """Uninstalls Chrome."""
263 if not self.GetChromeVersion():
264 raise RuntimeError('No Chrome version found on this system.')
265 chrome_path = self.GetChromeExePath()
266 install_type = self.GetChromeInstallationType()
267 reg_opts = self._GetUninstallArguments()
268 uninstall_str = self._GetUninstallString()
269 options = '%s --force-uninstall' % (reg_opts)
270 if self._type == InstallationType.SYSTEM:
271 options += ' --system-level'
272 if not os.path.exists(chrome_path):
273 logging.log(logging.ERROR, 'Could not find chrome, aborting uninstall.')
274 return False
275 logging.log(logging.INFO, 'Launching Chrome installer...')
276 ret = self._LaunchInstaller(uninstall_str, options)
277 if not os.path.exists(chrome_path):
278 logging.log(logging.INFO, 'Chrome was uninstalled successfully...')
279 # TODO: add clean option like ChromeInstaller
280 logging.log(logging.INFO, 'Deleting registry entries...')
281 self._DeleteChromeRegEntries()
282 logging.log(logging.INFO, 'Uninstall complete.')
283 return True
284 else:
285 logging.log(logging.ERROR, 'Uninstall failed.')
286 return False
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698