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

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

Powered by Google App Engine
This is Rietveld 408576698