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

Side by Side Diff: pyautolib/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 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 import os
7 import shutil
8 import ctypes
9 import urllib
10 import socket
11 import httplib
12 import _winreg
13 import tempfile
14 import platform
15 import urlparse
16 import subprocess
17
18 _PLATFORM = platform.system().lower()
19 _CSIDL_COMMON_APPDATA = 28
20 _CSIDL_PROGRAM_FILESX86 = 42
21
22 # Import only on Windows. On other platforms it will invoke a ValueError.
23 if _PLATFORM == 'windows':
24 from ctypes import wintypes, windll
25
26
27 class ChromeInstaller:
28 """This class is used to install or uninstall Chrome."""
29
30 def __init__(self, url, build, dest, opts='', clean=True):
31 self._url = (lambda u: u if self._DoesUrlExist(u) else '')(url)
32 self._dest = dest
33 self._opts = opts
34 self._clean = clean
35 self._type = (lambda o: 'system' if o.find('system-level') != -1 else
36 'user')(self._opts)
37 self._plat = 'win'
38 self._installer = 'mini_installer.exe'
39 self.SetCurrentBuild(build)
40 self.c_install = ChromeVersion(self._type)
41 self._c_path = self.c_install.GetChromeExePath()
42
43 def SetCurrentBuild(self, bld):
44 """Sets the build number that is to be installed."""
45 if type(bld) == str:
46 self.build = (lambda b: (all(map(lambda x: x.isdigit(), b.split('.')))
47 and len(b.split('.')) == 4) and b or '')(bld)
48 else:
49 self.build = ''
50
51 def _DoesUrlExist(self, url):
52 """Checks if a url exists.
53
54 Args:
55 url: URL to be verified.
56
57 Returns:
58 Boolean - True if the URL exists, otherwise False.
59 """
60 parse = urlparse.urlparse(url)
61 if parse[0] == '' or parse[1] == '':
62 return False
63 try:
64 conn = httplib.HTTPConnection(parse.netloc)
65 conn.request('HEAD', parse.path)
66 res = conn.getresponse()
67 except socket.gaierror:
68 return False
69 finally:
70 conn.close()
71 # Redirected - (301: permanently moved, 302: temporarily moved)
72 if res.status == 302 or res.status == 301:
73 return self._DoesUrlExist(res.getheader('location'))
74 return res.status == 200
75
76 def _Download(self, _file, url, dest=None):
77 """Downloads a file from the specified URL
78
79 Args:
80 _file: Name of the file to download.
81 url: URL where the file is located.
82 dest: Where file will be downloaded (optional). Default location is CWD.
83
84 Returns:
85 An integer - zero if successful, otherwise a non-zero value.
86 """
87 f_name = (lambda d, f: os.path.join(d, f) if(d and os.path.exists(d)) else
88 os.path.join(tempfile.gettempdir(), f))(dest, _file)
89 file_url = '%s/%s' % (url, _file)
90 # Check link before downloading, urlretrieve *WILL NOT* report
91 # an error if url doesn't exist.
92 if not self._DoesUrlExist(file_url):
93 print "Could not locate the file specified."
94 return -1
95 try:
96 d = urllib.urlretrieve(file_url, f_name)
97 except IOError, err:
98 print 'CChromeInstaller._Download: ', err
99 return -1
100 if os.path.isfile(d[0]):
101 return 0
102 return 1
103
104 def _Delete(self, _path):
105 """Deletes a file or folder"""
106 try:
107 (lambda p: shutil.rmtree(p) if os.path.isdir(p) else os.remove(p))(_path)
108 return 0
109 except(OSError, IOError, TypeError), err:
110 print 'CChromeInstaller._Delete: ', err
111 return -1
112
113 def _LaunchInstaller(self, opts=''):
114 """Launches the Chrome installer using specified options.
115
116 Args:
117 opts: Any options that are to be passed to the installer.
118
119 Returns:
120 An integer - zero if successful, otherwise a non-zero value.
121 """
122 print 'Downloading installer for build %s ...' % (self.build)
123 build_url = '%s/%s/%s' % (self._url, self.build, self._plat)
124 if self._Download(self._installer, build_url, self._dest) != 0:
125 print 'Failed to download installer, exiting test'
126 return -1
127 print 'Launching installer...'
128 cmd = '%s %s' % (os.path.join(self._dest, self._installer), opts)
129 try:
130 return subprocess.Popen.wait(subprocess.Popen(cmd))
131 except OSError, err:
132 print 'CChromeInstaller._LaunchInstaller: ', err
133 return -2
134
135 def _RemoveDuplicates(self, args):
136 """Removes duplicates from list of options.
137
138 Args:
139 args: A list containing the options.
140
141 Returns:
142 A string without any duplicate options.
143 """
144 return ((lambda arg: arg if arg else '')
145 (' '.join(map(lambda opt: opt, list(frozenset(args.split(',')))))))
146
147 def _DoPreliminaryChecks(self, op='install'):
148 """Checks test parameters for validity and performs version checking."""
149 if _PLATFORM != 'windows':
150 print 'Unsupported platform, aborting operation...'
151 return False
152 if self._url == '':
153 print 'URL specified is not valid. Please check the URL and try again.'
154 return False
155 ver = self.c_install.GetChromeVersion()
156 c_type = self.c_install.GetInstallTypeString()
157 if op == 'install':
158 self.pyauto_url = '%s/%s/%s/%s' % (self._url, self.build, 'win',
159 'chrome-win32.test')
160 if c_type == 'system' and self._type == 'user':
161 print 'System level Chrome exists, aborting user level installation.'
162 return False
163 # Version installed is higher than or same as the one we're installing.
164 elif self._type == c_type:
165 if self.build <= ver:
166 print 'Please specify a version higher than the one installed.'
167 return False
168 elif op == 'uninstall':
169 if not ver:
170 print 'No version of Chrome found, aborting uninstall...'
171 return False
172 if self._type != c_type:
173 print ('Invalid args passed. Please specify --opts=--system-level if '
174 'uninstalling system version of Chrome, or omit it otherwise.')
175 return False
176 return True
177
178 def InstallChrome(self):
179 """Installs specified chrome build."""
180 if not self._DoPreliminaryChecks('install'):
181 return None
182 opts = '--install --do-not-launch-chrome %s' % (self._opts)
183 opts = self._RemoveDuplicates(opts)
184 ret = self._LaunchInstaller(opts)
185 self._Delete(os.path.join(self._dest, self._installer))
186 if ret == 0 and os.path.exists(self._c_path):
187 print 'Installation complete...'
188 return self.c_install
189 else:
190 print 'Installation failed.'
191 return None
192
193 def UninstallChrome(self):
194 """Uninstalls Chrome."""
195 if not self._DoPreliminaryChecks('uninstall'):
196 return False
197 install_type = self.c_install.GetChromeInstallType()
198 reg_opts = self.c_install.GetUninstallArgs(install_type)
199 opts = '%s --force-uninstall %s' % (reg_opts, self._opts)
200 opts = self._RemoveDuplicates(opts)
201 if not os.path.exists(self._c_path):
202 print 'Couldn\'t find Chrome. Verify Chrome is installed and try again.'
203 return False
204 ret = self._LaunchInstaller(opts)
205 if os.path.exists(os.path.join(self._dest, self._installer)):
206 self._Delete(os.path.join(self._dest, self._installer))
207 if not os.path.exists(self._c_path):
208 print 'Chrome was successfully uninstalled...'
209 if self._clean:
210 print 'Removing registry settings...'
211 self.c_install.DeleteChromeRegEntries()
212 print 'Uninstall complete.'
213 return True
214 else:
215 print 'Uninstall failed.'
216 return False
217
218
219 class ChromeVersion():
220 """Contains utility functions that provide information about installed
221
222 version of Chrome. The type of Chrome version is passed as an argument
223 to the constructor (i.e. - user or system level version).
224 """
225
226 def __init__(self, install_type):
227 self._type = install_type
228 self.HKEY_LOCAL = (r'SOFTWARE\Wow6432Node\Google\Update\ClientState'
229 '\{8A69D345-D564-463C-AFF1-A69D9E530F96}')
230 self.HKEY_USER = self.HKEY_LOCAL.replace('\\Wow6432Node', '')
231
232 def _OpenKey(self, key_type, key_name, key_access=_winreg.KEY_READ):
233 """Opens a registry key.
234
235 Args:
236 key_type: HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE.
237 key_name: Name of the key that is to be opened.
238 key_access: Type of access required (i.e. - KEY_READ or KEY_ALL_ACCESS).
239
240 Returns:
241 Handle to the key if successful, otherwise zero.
242 """
243 try:
244 key = _winreg.OpenKey(key_type, key_name, 0, key_access)
245 return key
246 except(OSError, TypeError), err:
247 return 0
248
249 def _GetKeyValue(self, key, name):
250 """Gets the value of the specified key.
251
252 Args:
253 key: Handle to the key.
254 name: Name of the key.
255
256 Returns:
257 A string representing key value if successful, otherwise empty string.
258 """
259 try:
260 val = str(_winreg.QueryValueEx(key, name)[0])
261 return val
262 except OSError, err:
263 print 'ChromeVersion._GetKeyValue: %s' % (err)
264 return ''
265
266 def _GetKeyName(self, install_type, b_replace=True):
267 """Returns Chrome registry key name. """
268 if install_type == _winreg.HKEY_CURRENT_USER:
269 if b_replace:
270 return self.HKEY_USER.replace('ClientState', 'Clients')
271 else:
272 return self.HKEY_USER
273 elif install_type == _winreg.HKEY_LOCAL_MACHINE:
274 if b_replace:
275 return self.HKEY_LOCAL.replace('ClientState', 'Clients')
276 else:
277 return self.HKEY_LOCAL
278
279 def _GetWinLocalFolder(self, ftype=_CSIDL_COMMON_APPDATA):
280 """Returns the full path of the 'Local' folder on Windows.
281
282 Args:
283 ftype: Location to look up, which could vary based on installation type.
284
285 Returns:
286 A string containing the path if successful, otherwise an empty string.
287 """
288 if _PLATFORM != 'windows':
289 return ''
290 SHGetFolderPathW = windll.shell32.SHGetFolderPathW
291 SHGetFolderPathW.argtypes = [wintypes.HWND,
292 ctypes.c_int,
293 wintypes.HANDLE,
294 wintypes.DWORD,
295 wintypes.LPCWSTR]
296 path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
297 result = SHGetFolderPathW(0, ftype, 0, 0, path_buf)
298 return str(path_buf.value)
299
300 def GetInstallTypeString(self):
301 """Returns a string representing the type of Chrome installation."""
302 install_type = ({_winreg.HKEY_CURRENT_USER: 'user',
303 _winreg.HKEY_LOCAL_MACHINE: 'system'}).get(
304 self.GetChromeInstallType())
305 return install_type
306
307 def GetChromeInstallType(self):
308 """Determines Chrome installation type."""
309 c_type = None
310 key = self._OpenKey(_winreg.HKEY_CURRENT_USER,
311 self.HKEY_USER.replace('ClientState', 'Clients'))
312 if key:
313 if self._GetKeyValue(key, 'pv'):
314 c_type = _winreg.HKEY_CURRENT_USER
315 else:
316 key = self._OpenKey(_winreg.HKEY_LOCAL_MACHINE,
317 self.HKEY_USER.replace('ClientState', 'Clients'))
318 if key:
319 if self._GetKeyValue(key, 'pv'):
320 c_type = _winreg.HKEY_LOCAL_MACHINE
321 if key:
322 _winreg.CloseKey(key)
323 return c_type
324
325 def GetChromeVersion(self):
326 """Returns current Chrome version."""
327 chrome_ver = ''
328 key_type = ({'user': _winreg.HKEY_CURRENT_USER,
329 'system' : _winreg.HKEY_LOCAL_MACHINE}).get(self._type)
330 key = self._OpenKey(key_type, self._GetKeyName(key_type))
331 if key:
332 chrome_ver = self._GetKeyValue(key, 'pv')
333 _winreg.CloseKey(key)
334 return chrome_ver
335
336 def GetUninstallArgs(self, install_type=_winreg.HKEY_CURRENT_USER):
337 """Gets chrome's uninstall arguments from the registry.
338
339 Args:
340 install_type: Type of chrome installation (user or system).
341
342 Returns:
343 A string containing the arguments if successful, otherwise empty string.
344 """
345 c_args = ''
346 key = self._OpenKey(install_type, self._GetKeyName(install_type, False))
347 if key:
348 c_args = self._GetKeyValue(key, 'UninstallArguments')
349 _winreg.CloseKey(key)
350 return c_args
351
352 def GetChromeExePath(self):
353 """Gets Chrome's location, based on install type (i.e. user or system)."""
354 c_path = ''
355 f_id = (lambda _type: _type == 'user' and _CSIDL_COMMON_APPDATA or
356 _CSIDL_PROGRAM_FILESX86)(self._type)
357 if _PLATFORM == 'windows':
358 c_path = os.path.join(self._GetWinLocalFolder(f_id),
359 'Google', 'Chrome',
360 'Application', 'chrome.exe')
361 return c_path
362
363 def DeleteChromeRegEntries(self):
364 """Deletes chrome registry settings."""
365 if self._type == 'user':
366 p_key = self.HKEY_USER[: self.HKEY_USER.rfind('\\')]
367 key_name = self.HKEY_USER[self.HKEY_USER.rfind('\\') + 1 :]
368 _type = _winreg.HKEY_CURRENT_USER
369 else:
370 p_key = self.HKEY_LOCAL[: self.HKEY_LOCAL.rfind('\\')]
371 key_name = self.HKEY_LOCAL[self.HKEY_LOCAL.rfind('\\')+1:]
372 _type = _winreg.HKEY_LOCAL_MACHINE
373 key = self._OpenKey(_type, p_key, _winreg.KEY_ALL_ACCESS)
374 try:
375 _winreg.DeleteKey(key, key_name)
376 key.Close()
377 return 0
378 except _winreg.error, err:
379 print "Warning: could not delete registry settings - ", err
380 return -1
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698