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

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, 4 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
« no previous file with comments | « install_test/chrome_checkout.py ('k') | install_test/install_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 from ctypes import wintypes, windll
11 import httplib
12 import logging
13 import os
14 import shutil
15 import socket
16 import subprocess
17 import tempfile
18 import urllib
19
20
21 class InstallationType:
22 """Defines the Chrome installation types."""
23 SYSTEM = 0
24 USER = 1
25
26
27 class ChromeRegistryValues:
28 """Defines the Chrome registry key values."""
29 PRODUCT_VERSION = 0
kkania 2012/08/03 18:41:08 you can just change these values to the string equ
nkang 2012/08/06 23:57:13 Changed the three values from numerical to string.
30 UNINSTALL_ARGUMENTS = 1
31 UNINSTALL_STRING = 2
32
33
34 def Install(installer_path, chrome_type, build, options='', clean=True):
35 """Installs the specified Chrome build.
36
37 Args:
38 installer_path: Path to the Chrome installer.
39 chrome_type: Type of installation (i.e., system or user).
40 build: Chrome build number.
41 options: Any additional installation options.
42 clean: Determines whether to delete registry settings before installation.
43
44 Returns:
45 A ChromeInstallation object if successful, otherwise None.
kkania 2012/08/03 18:41:08 this comment needs to be updated
nkang 2012/08/06 23:57:13 Changed the comment. It now says, 'Returns: A Chro
46 """
47 def DoPreliminaryChecks(regedit):
48 """Validates the test parameters and Chrome version.
49
50 Args:
51 regedit: ChromeRegistryKeys object.
52 """
53 assert(os.path.isfile(installer_path))
54 install_type = ('system-level' in options and InstallationType.SYSTEM
kkania 2012/08/03 18:41:08 this statement no longer works. that is why I typi
nkang 2012/08/06 23:57:13 Good find! Changed this statement to the following
55 or InstallationType.USER)
56 cur_build = regedit.GetKeyValue(chrome_type,
57 ChromeRegistryValues.PRODUCT_VERSION)
58 # Chrome already installed, make sure new build can be installed over it.
59 if cur_build:
60 current_type = ChromeInstallation.GetType()
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 regedit = ChromeRegistryKeys()
71 DoPreliminaryChecks(regedit)
72 options += ' --install --do-not-launch-chrome'
73 logging.log(logging.INFO, 'Launching Chrome installer...')
74 cmd = '%s %s' % (installer_path, options)
75 ret = subprocess.Popen(cmd, shell=True).wait()
76 if ret == 0:
77 logging.log(logging.INFO, 'Installation complete.')
78 return ChromeInstallation(ChromeInstallation.GetType())
79 raise RuntimeError('Chrome installation for build %s failed.' % build)
80
81
82 class ChromeRegistryKeys(object):
83 """An interface for accessing and manipulating Chrome registry keys."""
84
85 _HKEY_LOCAL = r'SOFTWARE\Wow6432Node\Google\Update'
86 _HKEY_USER = _HKEY_LOCAL.replace('\\Wow6432Node', '')
87 _chrome_version = r'Clients\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
88 _chrome_uargs = r'ClientState\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
89 _chrome_ustring = r'ClientState\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
kkania 2012/08/03 18:41:08 what's diff between this and above var? merge them
nkang 2012/08/06 23:57:13 There's no difference; they are the same. I just c
90
91 def _GetKeyName(self, install_type, value):
92 """Generates the registry key name for the specified value.
93
94 Args:
95 install_type: Type of installation, must be InstallationType type.
96 value: ChromeRegistryValues type for which the key name is required.
97
98 Returns:
99 A string representing the full key name of the specified key value.
100 """
101 key_name = None
102 if install_type == InstallationType.USER:
103 key_name = self._HKEY_USER
104 elif install_type == InstallationType.SYSTEM:
105 key_name = self._HKEY_LOCAL
106 if value == ChromeRegistryValues.PRODUCT_VERSION:
107 return '%s\%s' % (key_name, self._chrome_version)
108 elif value == ChromeRegistryValues.UNINSTALL_ARGUMENTS:
109 return '%s\%s' % (key_name, self._chrome_uargs)
110 elif value == ChromeRegistryValues.UNINSTALL_STRING:
111 return '%s\%s' % (key_name, self._chrome_ustring)
112 return ''
kkania 2012/08/03 18:41:08 throw instead
nkang 2012/08/06 23:57:13 Instead of returning an empty string, the method n
113
114 def _GetRegistryType(self, install_type):
115 """Determines the registry key to use based on installation type.
116
117 Args:
118 install_type: Type of installation, must be InstallationType type.
119
120 Returns:
121 A long representing HKLM or HKCU, depending on installation type.
122 """
123 if install_type == InstallationType.SYSTEM:
124 return _winreg.HKEY_LOCAL_MACHINE
125 elif install_type == InstallationType.USER:
126 return _winreg.HKEY_CURRENT_USER
127 return None
kkania 2012/08/03 18:41:08 throw instead
nkang 2012/08/06 23:57:13 Instead of returning None, the method raises a Run
128
129 def DoesKeyExist(self, install_type, subkey):
130 """Determines if a particular key exists in the registry.
131
132 Args:
133 install_type: Type of installation, must be InstallationType type.
134 subkey: Subkey to look up. It must be a ChromeRegistryValues type.
135
136 Returns:
137 True if the key exists, otherwise False.
138 """
139 b_exists = False
140 key = self._GetRegistryType(install_type)
141 key_name = self._GetKeyName(install_type, subkey)
142 if not key_name or not key:
143 return b_exists
kkania 2012/08/03 18:41:08 throw instead
nkang 2012/08/06 23:57:13 Got rid of this statement altogether. We can't thr
144 try:
145 hkey = _winreg.OpenKey(key, key_name)
146 if hkey.handle:
147 b_exists = True
148 hkey.Close()
149 return b_exists
150 except _winreg.error:
151 return False
152
153 def GetKeyValue(self, install_type, subkey):
154 """Gets value of the specified subkey from the registry.
155
156 Args:
157 install_type: Type of installation, must be InstallationType type.
158 subkey: ChromeRegistryValue type representing the value to be returned.
159
160 Returns:
161 A string representing the subkey value if successful, otherwise None.
kkania 2012/08/03 18:41:08 don't return none in this func in any circumstance
nkang 2012/08/06 23:57:13 Got rid of the None return value if a _winreg.erro
162 """
163 reg_value = ''
164 key = self._GetRegistryType(install_type)
165 key_name = self._GetKeyName(install_type, subkey)
166 value = ({ChromeRegistryValues.PRODUCT_VERSION : 'pv',
167 ChromeRegistryValues.UNINSTALL_STRING : 'UninstallString',
168 ChromeRegistryValues.UNINSTALL_ARGUMENTS : 'UninstallArguments'
169 }).get(subkey)
170 if not key or not key_name:
kkania 2012/08/03 18:41:08 don't check here, let the other funcs throw
nkang 2012/08/06 23:57:13 Got rid of the 'if' statement, altogether. If key
171 return None
172 try:
173 hkey = _winreg.OpenKey(key, key_name)
kkania 2012/08/03 18:41:08 don't catch exceptions here, let them be raised
nkang 2012/08/06 23:57:13 Got rid of the try/except block. We will no longer
174 if hkey.handle:
175 reg_value = str(_winreg.QueryValueEx(hkey, value)[0])
176 hkey.Close()
177 return reg_value
178 except _winreg.error:
179 return None
180
181 def DeleteRegistryEntries(self, install_type):
182 """Deletes chrome registry settings.
183
184 Args:
185 install_type: Type of installation, must be InstallationType type.
186 """
187 key = self._GetRegistryType(install_type)
188 key_name = self._GetKeyName(install_type,
189 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
190 root = key_name[: key_name.rfind('\\')]
kkania 2012/08/03 18:41:08 no space between :
nkang 2012/08/06 23:57:13 Fixed.
191 child = key_name[key_name.rfind('\\') + 1 :]
kkania 2012/08/03 18:41:08 same
nkang 2012/08/06 23:57:13 Fixed.
192 try:
193 key = _winreg.OpenKey(key, root, 0, _winreg.KEY_ALL_ACCESS)
194 _winreg.DeleteKey(key, child)
195 key.Close()
196 except _winreg.error, err:
kkania 2012/08/03 18:41:08 why bother catching if you're just going to raise?
nkang 2012/08/06 23:57:13 Previously 'DeleteRegistryEntries' did not raise a
197 raise(err)
198
199
200 class ChromeInstallation(object):
201 """Provides pertinent information about the installed Chrome version.
202
203 The type of Chrome version must be passed as an argument to the constructor,
204 (i.e. - user or system level).
205 """
206
207 _CSIDL_COMMON_APPDATA = 0x1C
208 _CSIDL_PROGRAM_FILESX86 = 0x2A
209
210 def __init__(self, install_type):
211 assert(install_type == InstallationType.SYSTEM or
212 install_type == InstallationType.USER)
213 self._type = install_type
214 self._regedit = ChromeRegistryKeys()
215
216 def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
217 """Returns full path of the 'Local' folder on Windows.
218
219 Args:
220 ftype: Location to look up, which could vary based on installation type.
221
222 Returns:
223 A String representing the folder path if successful, otherwise an empty
224 string.
225 """
226 SHGetFolderPathW = windll.shell32.SHGetFolderPathW
227 SHGetFolderPathW.argtypes = [wintypes.HWND,
228 ctypes.c_int,
229 wintypes.HANDLE,
230 wintypes.DWORD,
231 wintypes.LPCWSTR]
232 path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
233 result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
234 return str(path_buf.value)
235
236 def _GetUninstallString(self):
237 """Returns the Chrome uninstall string from the registry."""
238 return self._regedit.GetKeyValue(self._type,
239 ChromeRegistryValues.UNINSTALL_STRING)
240
241 def _GetUninstallArguments(self):
242 """Returns the Chrome uninstall arguments from the registry."""
243 return self._regedit.GetKeyValue(self._type,
244 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
245
246 def _LaunchInstaller(self, installer_path, options):
kkania 2012/08/03 18:41:08 remove this separate func and put subproces.popen
nkang 2012/08/06 23:57:13 Got rid of the '_LaunchInstaller' method. The whol
247 """Launches the Chrome installer.
248
249 Args:
250 installer_path: Path where the installer is located.
251 options: Any additional options to be used for installation.
252 """
253 cmd = '%s %s' % (installer_path, options)
254 try:
255 subprocess.Popen(cmd, shell=True).wait()
256 except OSError, err:
257 raise err
258
259 def GetPath(self):
kkania 2012/08/03 18:41:08 GetExePath
nkang 2012/08/06 23:57:13 Changed method name to GetExePath.
260 """Returns Chrome binary location based on installation type."""
261 if self._type == InstallationType.USER:
262 folder_id = self._CSIDL_COMMON_APPDATA
263 elif self._type == InstallationType.SYSTEM:
264 folder_id = self._CSIDL_PROGRAM_FILESX86
265 chrome_path = os.path.join(self._GetWinLocalFolder(folder_id), 'Google',
266 'Chrome', 'Application', 'chrome.exe')
267 return (os.path.exists(chrome_path) and chrome_path or '')
268
269 @staticmethod
270 def GetType():
kkania 2012/08/03 18:41:08 change this to GetCurrent, which returns None or a
nkang 2012/08/06 23:57:13 Changed method name to GetCurrent. Also changed th
271 """Determines Chrome installation type.
272
273 Returns:
274 InstallationType type if Chrome is present, otherwise None.
275 """
276 registry = ChromeRegistryKeys()
277 if registry.DoesKeyExist(InstallationType.SYSTEM,
278 ChromeRegistryValues.PRODUCT_VERSION):
279 return InstallationType.SYSTEM
280 elif registry.DoesKeyExist(InstallationType.USER,
281 ChromeRegistryValues.PRODUCT_VERSION):
282 return InstallationType.USER
283 return None
284
285 def Uninstall(self):
286 """Uninstalls Chrome."""
287 install_type = ChromeInstallation.GetType()
kkania 2012/08/03 18:41:08 don't do this
nkang 2012/08/06 23:57:13 Fine, I won't :)
288 if not install_type:
289 raise RuntimeError('No Chrome version found on this system.')
290 chrome_path = self.GetPath()
291 reg_opts = self._GetUninstallArguments()
292 uninstall_str = self._GetUninstallString()
293 options = '%s --force-uninstall' % (reg_opts)
294 if self._type == InstallationType.SYSTEM:
295 options += ' --system-level'
296 if not os.path.exists(chrome_path):
297 raise RuntimeError('Could not find chrome, aborting uninstall.')
298 logging.log(logging.INFO, 'Launching Chrome installer...')
299 self._LaunchInstaller(uninstall_str, options)
300 if not os.path.exists(chrome_path):
301 logging.log(logging.INFO, 'Chrome was uninstalled successfully...')
302 logging.log(logging.INFO, 'Deleting registry entries...')
303 self._regedit.DeleteRegistryEntries(self._type)
304 logging.log(logging.INFO, 'Uninstall complete.')
305 else:
306 raise RuntimeError('Uninstall failed.')
OLDNEW
« no previous file with comments | « install_test/chrome_checkout.py ('k') | install_test/install_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698