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

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.
7
8 At present the only platform it supports is Windows.
Nirnimesh 2012/08/22 07:06:35 rename the file to append _win to the name. You'll
nkang 2012/08/24 22:45:26 Changed name to chrome_installer_win.py. Updated o
9 """
10
11 import _winreg
12 import ctypes
13 from ctypes import wintypes, windll
14 import httplib
15 import logging
16 import os
17 import shutil
18 import socket
19 import subprocess
20 import tempfile
21 import urllib
22
23
24 class InstallationType(object):
25 """Defines the Chrome installation types."""
26 SYSTEM = 0
Nirnimesh 2012/08/22 07:06:35 If you're going to do if calls on this, make it no
nkang 2012/08/24 22:45:26 Done. Added a third variable called NOT_INSTALLED.
27 USER = 1
28
29
30 class ChromeRegistryValues(object):
31 """Defines the Chrome registry key values."""
32 PRODUCT_VERSION = 'pv'
33 UNINSTALL_STRING = 'UninstallString'
34 UNINSTALL_ARGUMENTS = 'UninstallArguments'
35
36
37 def Install(installer_path, install_type, build, options=''):
38 """Installs the specified Chrome build.
39
40 Args:
41 installer_path: Path to the Chrome installer.
42 install_type: Type of installation (i.e., system or user).
43 build: Chrome build number.
44 options: Any additional installation options.
Nirnimesh 2012/08/22 07:06:35 remove 'Any'
Nirnimesh 2012/08/22 07:06:35 make it a list instead of having to split by ' ' a
nkang 2012/08/24 22:45:26 Changed options to a list. For this I also had to
nkang 2012/08/24 22:45:26 Removed 'Any'.
45
46 Returns:
47 An instance of ChromeInstallation.
48 """
49 def _DoPreliminaryChecks(regedit):
50 """Validates the test parameters and Chrome version.
51
52 Checks if a Chrome version is already installed on the system. If so it
53 confirms that the version specified by the user is higher than the one
54 currently installed. It also checks to make sure the installation type
55 is valid, as a user level version cannot be installed over an existing
56 system level version of Chrome.
57
58 Args:
59 regedit: ChromeRegistryKeys object.
60 """
61 current_type = None
62 # Check if Chrome is already installed on the system.
63 if regedit.DoesKeyExist(InstallationType.USER,
64 ChromeRegistryValues.PRODUCT_VERSION):
65 current_type = InstallationType.USER
66 elif regedit.DoesKeyExist(InstallationType.SYSTEM,
67 ChromeRegistryValues.PRODUCT_VERSION):
68 current_type = InstallationType.SYSTEM
69 if current_type != None:
Nirnimesh 2012/08/22 07:06:35 remove "!= None"
nkang 2012/08/24 22:45:26 Changed the InstallationType class and created a t
70 # Make sure new build can be installed over existing Chrome build.
71 if (current_type == InstallationType.SYSTEM and install_type ==
Nirnimesh 2012/08/22 07:06:35 move install_type == to the next line
nkang 2012/08/24 22:45:26 Moved 'install_type' to the next line.
72 InstallationType.USER):
73 raise RuntimeError('System level Chrome exists, aborting user level '
74 'installation.')
75 build_num = regedit.GetKeyValue(current_type,
76 ChromeRegistryValues.PRODUCT_VERSION)
77 # Confirm the new Chrome build is higher than the installed build.
78 if build_num >= build:
79 raise RuntimeError('Specify a version higher than the one already '
80 'installed.')
81
82 regedit = ChromeRegistryKeys()
83 _DoPreliminaryChecks(regedit)
84 options = '%s %s' % (options, '--install --do-not-launch-chrome')
Nirnimesh 2012/08/22 07:06:35 remove the last %s and move the strings there dire
nkang 2012/08/24 22:45:26 Got rid of the last %s and moved the strings there
85 logging.log(logging.INFO, 'Launching Chrome installer...')
86 args = [installer_path]
87 args.extend(options.split(' '))
88 ret = subprocess.Popen(args).wait()
Nirnimesh 2012/08/22 07:06:35 use a better varname. It looks like you don't even
nkang 2012/08/24 22:45:26 Got rid of this arg. Moved the 'if' statement to t
89 if ret != 0:
90 raise RuntimeError('Chrome installation for build %s failed.' % build)
91 logging.log(logging.INFO, 'Installation complete.')
92 return ChromeInstallation.GetCurrent()
93
94
95 class ChromeRegistryKeys(object):
96 """An interface for accessing and manipulating Chrome registry keys."""
97
98 _HKEY_LOCAL = r'SOFTWARE\Wow6432Node\Google\Update'
99 _HKEY_USER = _HKEY_LOCAL.replace(r'\Wow6432Node', '')
100 _chrome_version = r'Clients\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
101 _chrome_args = r'ClientState\{8A69D345-D564-463C-AFF1-A69D9E530F96}'
Nirnimesh 2012/08/22 07:06:35 Why is this lower case, whereas line 98,99 are in
nkang 2012/08/24 22:45:26 It's just because the names HKEY_USER and HKEY_LOC
102
103 def _GetKeyName(self, install_type, value):
104 """Gets the registry key name for the specified value.
105
106 Args:
107 install_type: Type of installation, must be InstallationType type.
108 value: ChromeRegistryValues type for which the key name is required.
109
110 Returns:
111 A string representing the full key name of the specified key value.
112 """
113 key_name = None
114 if install_type == InstallationType.USER:
115 key_name = self._HKEY_USER
116 elif install_type == InstallationType.SYSTEM:
117 key_name = self._HKEY_LOCAL
118 if value == ChromeRegistryValues.PRODUCT_VERSION:
119 return '%s\%s' % (key_name, self._chrome_version)
120 elif value == ChromeRegistryValues.UNINSTALL_ARGUMENTS:
121 return '%s\%s' % (key_name, self._chrome_args)
122 elif value == ChromeRegistryValues.UNINSTALL_STRING:
123 return '%s\%s' % (key_name, self._chrome_args)
124 raise RuntimeError('Invalid registry value.')
125
126 def _GetRegistryType(self, install_type):
127 """Determines the registry key to use based on installation type.
128
129 Args:
130 install_type: Type of installation, must be InstallationType type.
131
132 Returns:
133 A long representing HKLM or HKCU, depending on installation type.
134 """
135 if install_type == InstallationType.SYSTEM:
136 return _winreg.HKEY_LOCAL_MACHINE
137 elif install_type == InstallationType.USER:
138 return _winreg.HKEY_CURRENT_USER
139 raise RuntimeError('Invalid installation type.')
140
141 def DoesKeyExist(self, install_type, subkey):
142 """Determines if a particular key exists in the registry.
143
144 Args:
145 install_type: Type of installation, must be InstallationType type.
146 subkey: Subkey to look up. It must be a ChromeRegistryValues type.
147
148 Returns:
149 True if the key exists, otherwise False.
150 """
151 key = self._GetRegistryType(install_type)
152 key_name = self._GetKeyName(install_type, subkey)
153 try:
154 hkey = _winreg.OpenKey(key, key_name)
Nirnimesh 2012/08/22 07:06:35 only this line needs to be in the try block right?
nkang 2012/08/24 22:45:26 Done.
155 if not hkey.handle:
156 return False
157 hkey.Close()
158 return True
159 except _winreg.error:
160 return False
161
162 def GetKeyValue(self, install_type, subkey):
163 """Gets value of the specified subkey from the registry.
164
165 Args:
166 install_type: Type of installation, must be InstallationType type.
167 subkey: ChromeRegistryValue type representing the value to be returned.
168
169 Returns:
170 A string representing the subkey value.
171 """
172 reg_value = ''
173 key = self._GetRegistryType(install_type)
174 key_name = self._GetKeyName(install_type, subkey)
175 hkey = _winreg.OpenKey(key, key_name)
176 if hkey.handle:
177 reg_value = str(_winreg.QueryValueEx(hkey, subkey)[0])
178 hkey.Close()
179 return reg_value
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 reg_type = self._GetRegistryType(install_type)
188 key_name = self._GetKeyName(install_type,
189 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
190 root = key_name[:key_name.rfind('\\')]
191 child = key_name[key_name.rfind('\\') + 1:]
192 key = _winreg.OpenKey(reg_type, root, 0, _winreg.KEY_ALL_ACCESS)
193 _winreg.DeleteKey(key, child)
194 key.Close()
195
196
197 class ChromeInstallation(object):
198 """Provides pertinent information about the installed Chrome version.
199
200 The type of Chrome version must be passed as an argument to the constructor,
201 (i.e. - user or system level).
202 """
203
204 _CSIDL_COMMON_APPDATA = 0x1C
205 _CSIDL_PROGRAM_FILESX86 = 0x2A
206
207 def __init__(self, install_type):
208 assert(install_type == InstallationType.SYSTEM or
209 install_type == InstallationType.USER)
210 self._type = install_type
211 self._regedit = ChromeRegistryKeys()
212
213 def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
214 """Returns full path of the 'Local' folder on Windows.
215
216 Args:
217 ftype: Location to look up, which could vary based on installation type.
218
219 Returns:
220 A String representing the folder path if successful, otherwise an empty
221 string.
222 """
223 SHGetFolderPathW = windll.shell32.SHGetFolderPathW
224 SHGetFolderPathW.argtypes = [wintypes.HWND,
225 ctypes.c_int,
226 wintypes.HANDLE,
227 wintypes.DWORD,
228 wintypes.LPCWSTR]
229 path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
230 result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
231 return str(path_buf.value)
232
233 def _GetUninstallString(self):
234 """Returns the Chrome uninstall string from the registry."""
235 return self._regedit.GetKeyValue(self._type,
236 ChromeRegistryValues.UNINSTALL_STRING)
237
238 def _GetUninstallArguments(self):
239 """Returns the Chrome uninstall arguments from the registry."""
240 return self._regedit.GetKeyValue(self._type,
241 ChromeRegistryValues.UNINSTALL_ARGUMENTS)
242
243 def GetExePath(self):
244 """Returns Chrome binary location based on installation type."""
245 if self._type == InstallationType.USER:
246 folder_id = self._CSIDL_COMMON_APPDATA
247 elif self._type == InstallationType.SYSTEM:
248 folder_id = self._CSIDL_PROGRAM_FILESX86
249 chrome_path = os.path.join(self._GetWinLocalFolder(folder_id), 'Google',
250 'Chrome', 'Application', 'chrome.exe')
251 return (chrome_path if os.path.exists(chrome_path) else '')
252
253 @staticmethod
254 def GetCurrent():
255 """Determines Chrome installation type.
256
257 Returns:
258 ChromeInstallation object if Chrome is present, otherwise None.
259 """
260 registry = ChromeRegistryKeys()
261 if registry.DoesKeyExist(InstallationType.SYSTEM,
262 ChromeRegistryValues.PRODUCT_VERSION):
263 return ChromeInstallation(InstallationType.SYSTEM)
264 elif registry.DoesKeyExist(InstallationType.USER,
265 ChromeRegistryValues.PRODUCT_VERSION):
266 return ChromeInstallation(InstallationType.USER)
267 return None
268
269 def Uninstall(self):
270 """Uninstalls Chrome."""
271 chrome_path = self.GetExePath()
272 reg_opts = self._GetUninstallArguments()
273 uninstall_str = self._GetUninstallString()
Nirnimesh 2012/08/22 07:06:35 does this not contain .exe?
nkang 2012/08/24 22:45:26 The UninstallString contains the path to the insta
274 options = '%s --force-uninstall' % (reg_opts)
275 if self._type == InstallationType.SYSTEM:
276 options += ' --system-level'
277 if not os.path.exists(chrome_path):
278 raise RuntimeError('Could not find chrome, aborting uninstall.')
279 logging.log(logging.INFO, 'Launching Chrome installer...')
280 cmd = '"%s" %s' % (uninstall_str, options)
281 subprocess.Popen(cmd, shell=True).wait()
Nirnimesh 2012/08/22 07:06:35 subprocess.call()
nkang 2012/08/24 22:45:26 Done.
282 if not os.path.exists(chrome_path):
283 logging.log(logging.INFO, 'Chrome was uninstalled successfully...')
Nirnimesh 2012/08/22 07:06:35 Instead of using logging.log(logging.INFO, ...), u
nkang 2012/08/24 22:45:26 Updated everywhere logging.log was used in chrome_
284 logging.log(logging.INFO, 'Deleting registry entries...')
285 self._regedit.DeleteRegistryEntries(self._type)
286 logging.log(logging.INFO, 'Uninstall complete.')
287 else:
288 raise RuntimeError('Uninstall failed.')
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698