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

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
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."""
Nirnimesh 2012/08/09 21:32:48 Is this supposed to be for win only? If so, mentio
nkang 2012/08/16 23:46:24 Added a line that mentions that currently the only
7
8 import _winreg
Nirnimesh 2012/08/09 21:32:48 will fail on non-win
nkang 2012/08/16 23:46:24 Previously I had a check in here that only importe
Nirnimesh 2012/08/22 07:06:34 You know that it's supposed to be used on win beca
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:
Nirnimesh 2012/08/09 21:32:48 inherit from object
nkang 2012/08/16 23:46:24 Done.
22 """Defines the Chrome installation types."""
23 SYSTEM = 0
24 USER = 1
25
26
27 class ChromeRegistryValues:
Nirnimesh 2012/08/09 21:32:48 inherit from object
nkang 2012/08/16 23:46:24 Done.
28 """Defines the Chrome registry key values."""
29 PRODUCT_VERSION = 'pv'
30 UNINSTALL_STRING = 'UninstallString'
31 UNINSTALL_ARGUMENTS = 'UninstallArguments'
32
33
34 def Install(installer_path, install_type, build, options=''):
35 """Installs the specified Chrome build.
36
37 Args:
38 installer_path: Path to the Chrome installer.
39 install_type: Type of installation (i.e., system or user).
40 build: Chrome build number.
41 options: Any additional installation options.
42
43 Returns:
44 A ChromeInstallation object.
Nirnimesh 2012/08/09 21:32:48 an instance of ChromeInstallation.
nkang 2012/08/16 23:46:24 Done.
45 """
46 def DoPreliminaryChecks(regedit):
Nirnimesh 2012/08/09 21:32:48 prefix _
nkang 2012/08/16 23:46:24 Done.
47 """Validates the test parameters and Chrome version.
Nirnimesh 2012/08/09 21:32:48 Be more specific. Call out exactly what it does.
nkang 2012/08/16 23:46:24 Updated the docstring, so its more descriptive.
48
49 Args:
50 regedit: ChromeRegistryKeys object.
51 """
52 assert(os.path.isfile(installer_path))
Nirnimesh 2012/08/09 21:32:48 why?
nkang 2012/08/16 23:46:24 The installer was initially downloaded by a class
53 current_type = None
54 # Check if Chrome is already installed on the system.
55 if regedit.DoesKeyExist(InstallationType.USER,
56 ChromeRegistryValues.PRODUCT_VERSION):
57 current_type = InstallationType.USER
58 elif regedit.DoesKeyExist(InstallationType.SYSTEM,
59 ChromeRegistryValues.PRODUCT_VERSION):
60 current_type = InstallationType.SYSTEM
61 if current_type != None:
Nirnimesh 2012/08/09 21:32:48 remove "!= None"
nkang 2012/08/16 23:46:24 I explicitly added '!= None' because if a Chrome v
Nirnimesh 2012/08/22 07:06:34 That sounds bizarre. Why not add another installat
nkang 2012/08/24 22:45:26 Added a third variable called NOT_INSTALLED and se
62 # Make sure new build can be installed over existing Chrome build.
63 if (current_type == InstallationType.SYSTEM and install_type ==
64 InstallationType.USER):
65 raise RuntimeError('System level Chrome exists, aborting user level '
66 'installation.')
67 build_num = regedit.GetKeyValue(current_type,
68 ChromeRegistryValues.PRODUCT_VERSION)
69 # Confirm that the new Chrome build is higher than the installed build.
70 if build_num >= build:
71 raise RuntimeError('Please specify a version higher than the one '
Nirnimesh 2012/08/09 21:32:48 Remove "Please"
nkang 2012/08/16 23:46:24 Sorry, I was just trying to be courteous. But, res
72 'already installed.')
73
74 regedit = ChromeRegistryKeys()
75 DoPreliminaryChecks(regedit)
76 options += ' --install --do-not-launch-chrome'
77 logging.log(logging.INFO, 'Launching Chrome installer...')
78 cmd = '%s %s' % (installer_path, options)
Nirnimesh 2012/08/09 21:32:48 either use + to join strings (line 76), or use thi
nkang 2012/08/16 23:46:24 Got rid of the +=. I now use string formatting to
79 ret = subprocess.Popen(cmd, shell=True).wait()
Nirnimesh 2012/08/09 21:32:48 make cmd a list. remove shell=True
nkang 2012/08/16 23:46:24 Made cmd a list and got rid of shell=True.
80 if ret == 0:
Nirnimesh 2012/08/09 21:32:48 Invert the logic. Raise first if ret != 0
nkang 2012/08/16 23:46:24 Inverted the logic. An exception is now raised if
81 logging.log(logging.INFO, 'Installation complete.')
82 return ChromeInstallation.GetCurrent()
83 raise RuntimeError('Chrome installation for build %s failed.' % build)
84
85
86 class ChromeRegistryKeys(object):
87 """An interface for accessing and manipulating Chrome registry keys."""
88
89 _HKEY_LOCAL = r'SOFTWARE\Wow6432Node\Google\Update'
90 _HKEY_USER = _HKEY_LOCAL.replace('\\Wow6432Node', '')
Nirnimesh 2012/08/09 21:32:48 either use r'..' or \\ thoughout.
nkang 2012/08/16 23:46:24 Changed to r'..'.
91 _chrome_version = r'Clients\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
92 _chrome_args = r'ClientState\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
93
94 def _GetKeyName(self, install_type, value):
95 """Generates the registry key name for the specified value.
Nirnimesh 2012/08/09 21:32:48 Generate -> Get
nkang 2012/08/16 23:46:24 Done.
96
97 Args:
98 install_type: Type of installation, must be InstallationType type.
99 value: ChromeRegistryValues type for which the key name is required.
100
101 Returns:
102 A string representing the full key name of the specified key value.
103 """
104 key_name = None
105 if install_type == InstallationType.USER:
106 key_name = self._HKEY_USER
107 elif install_type == InstallationType.SYSTEM:
108 key_name = self._HKEY_LOCAL
109 if value == ChromeRegistryValues.PRODUCT_VERSION:
110 return '%s\%s' % (key_name, self._chrome_version)
111 elif value == ChromeRegistryValues.UNINSTALL_ARGUMENTS:
112 return '%s\%s' % (key_name, self._chrome_args)
113 elif value == ChromeRegistryValues.UNINSTALL_STRING:
114 return '%s\%s' % (key_name, self._chrome_args)
115 raise RuntimeError('Invalid registry value.')
116
117 def _GetRegistryType(self, install_type):
118 """Determines the registry key to use based on installation type.
119
120 Args:
121 install_type: Type of installation, must be InstallationType type.
122
123 Returns:
124 A long representing HKLM or HKCU, depending on installation type.
125 """
126 if install_type == InstallationType.SYSTEM:
127 return _winreg.HKEY_LOCAL_MACHINE
128 elif install_type == InstallationType.USER:
129 return _winreg.HKEY_CURRENT_USER
130 raise RuntimeError('Invalid installation type.')
131
132 def DoesKeyExist(self, install_type, subkey):
133 """Determines if a particular key exists in the registry.
134
135 Args:
136 install_type: Type of installation, must be InstallationType type.
137 subkey: Subkey to look up. It must be a ChromeRegistryValues type.
138
139 Returns:
140 True if the key exists, otherwise False.
141 """
142 b_exists = False
Nirnimesh 2012/08/09 21:32:48 remove "b_"
nkang 2012/08/16 23:46:24 Got rid of the boolean var, so this no longer appl
143 key = self._GetRegistryType(install_type)
144 key_name = self._GetKeyName(install_type, subkey)
145 try:
146 hkey = _winreg.OpenKey(key, key_name)
147 if hkey.handle:
148 b_exists = True
149 hkey.Close()
Nirnimesh 2012/08/09 21:32:48 If you just return True from here, you don't even
nkang 2012/08/16 23:46:24 Done. Got rid of the boolean var.
150 return b_exists
151 except _winreg.error:
152 return False
153
154 def GetKeyValue(self, install_type, subkey):
155 """Gets value of the specified subkey from the registry.
156
157 Args:
158 install_type: Type of installation, must be InstallationType type.
159 subkey: ChromeRegistryValue type representing the value to be returned.
160
161 Returns:
162 A string representing the subkey value.
163 """
164 reg_value = ''
165 key = self._GetRegistryType(install_type)
166 key_name = self._GetKeyName(install_type, subkey)
167 hkey = _winreg.OpenKey(key, key_name)
168 if hkey.handle:
169 reg_value = str(_winreg.QueryValueEx(hkey, subkey)[0])
170 hkey.Close()
171 return reg_value
172
173 def DeleteRegistryEntries(self, install_type):
174 """Deletes chrome registry settings.
175
176 Args:
177 install_type: Type of installation, must be InstallationType type.
178 """
179 reg_type = self._GetRegistryType(install_type)
180 key_name = self._GetKeyName(install_type,
181 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
182 root = key_name[:key_name.rfind('\\')]
183 child = key_name[key_name.rfind('\\') + 1:]
184 key = _winreg.OpenKey(reg_type, root, 0, _winreg.KEY_ALL_ACCESS)
185 _winreg.DeleteKey(key, child)
186 key.Close()
187
188
189 class ChromeInstallation(object):
190 """Provides pertinent information about the installed Chrome version.
191
192 The type of Chrome version must be passed as an argument to the constructor,
193 (i.e. - user or system level).
194 """
195
196 _CSIDL_COMMON_APPDATA = 0x1C
197 _CSIDL_PROGRAM_FILESX86 = 0x2A
198
199 def __init__(self, install_type):
200 assert(install_type == InstallationType.SYSTEM or
201 install_type == InstallationType.USER)
202 self._type = install_type
203 self._regedit = ChromeRegistryKeys()
204
205 def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
206 """Returns full path of the 'Local' folder on Windows.
207
208 Args:
209 ftype: Location to look up, which could vary based on installation type.
210
211 Returns:
212 A String representing the folder path if successful, otherwise an empty
213 string.
214 """
215 SHGetFolderPathW = windll.shell32.SHGetFolderPathW
216 SHGetFolderPathW.argtypes = [wintypes.HWND,
217 ctypes.c_int,
218 wintypes.HANDLE,
219 wintypes.DWORD,
220 wintypes.LPCWSTR]
221 path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
222 result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
223 return str(path_buf.value)
224
225 def _GetUninstallString(self):
226 """Returns the Chrome uninstall string from the registry."""
227 return self._regedit.GetKeyValue(self._type,
228 ChromeRegistryValues.UNINSTALL_STRING)
229
230 def _GetUninstallArguments(self):
231 """Returns the Chrome uninstall arguments from the registry."""
232 return self._regedit.GetKeyValue(self._type,
233 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
234
235 def GetExePath(self):
236 """Returns Chrome binary location based on installation type."""
237 if self._type == InstallationType.USER:
238 folder_id = self._CSIDL_COMMON_APPDATA
239 elif self._type == InstallationType.SYSTEM:
240 folder_id = self._CSIDL_PROGRAM_FILESX86
241 chrome_path = os.path.join(self._GetWinLocalFolder(folder_id), 'Google',
Nirnimesh 2012/08/09 21:32:48 What about Chromium?
nkang 2012/08/16 23:46:24 Per Anantha, we will not be using Chromium.
Nirnimesh 2012/08/22 07:06:34 Do you declare this somewhere in the docs?
nkang 2012/08/24 22:45:26 I checked with Ken on this, and he advised to decl
242 'Chrome', 'Application', 'chrome.exe')
243 return (chrome_path if os.path.exists(chrome_path) else '')
244
245 @staticmethod
246 def GetCurrent():
247 """Determines Chrome installation type.
248
249 Returns:
250 ChromeInstallation object if Chrome is present, otherwise None.
251 """
252 registry = ChromeRegistryKeys()
253 if registry.DoesKeyExist(InstallationType.SYSTEM,
254 ChromeRegistryValues.PRODUCT_VERSION):
255 return ChromeInstallation(InstallationType.SYSTEM)
256 elif registry.DoesKeyExist(InstallationType.USER,
257 ChromeRegistryValues.PRODUCT_VERSION):
258 return ChromeInstallation(InstallationType.USER)
259 return None
260
261 def Uninstall(self):
262 """Uninstalls Chrome."""
263 chrome_path = self.GetExePath()
264 reg_opts = self._GetUninstallArguments()
265 uninstall_str = self._GetUninstallString()
266 options = '%s --force-uninstall' % (reg_opts)
267 if self._type == InstallationType.SYSTEM:
268 options += ' --system-level'
269 if not os.path.exists(chrome_path):
270 raise RuntimeError('Could not find chrome, aborting uninstall.')
271 logging.log(logging.INFO, 'Launching Chrome installer...')
272 cmd = '"%s" %s' % (uninstall_str, options)
273 subprocess.Popen(cmd, shell=True).wait()
274 if not os.path.exists(chrome_path):
275 logging.log(logging.INFO, 'Chrome was uninstalled successfully...')
276 logging.log(logging.INFO, 'Deleting registry entries...')
277 self._regedit.DeleteRegistryEntries(self._type)
278 logging.log(logging.INFO, 'Uninstall complete.')
279 else:
280 raise RuntimeError('Uninstall failed.')
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698