# -*- coding: utf-8 -*- ########################################################################## # # pgAdmin 4 - PostgreSQL Tools # # Copyright (C) 2013 - 2020, The pgAdmin Development Team # This software is released under the PostgreSQL Licence # ########################################################################## # Get the correct version of chromedriver for the version of Chrome on the # machine and save it to the specified location. import argparse import os import platform import subprocess import sys try: from urllib.request import urlopen, urlretrieve from urllib.error import URLError except Exception: from urllib import urlopen, urlretrieve URLError = Exception import zipfile def read_command_line(): """Read the command line arguments. Returns: ArgumentParser: The parsed arguments object """ parser = argparse.ArgumentParser( description='Get the correct version of chromedriver for the ' 'specified Chrome installation and save it.') if platform.system() != 'Windows': parser.add_argument("chrome", metavar="CHROME", help="the Chrome executable") parser.add_argument("directory", metavar="DIRECTORY", help="the directory in which to save chromedriver") args = parser.parse_args() return args def get_chrome_version(args): """Get the Chrome version number. Args: args: The parsed arguments object Returns: The Chrome version number """ if platform.system() == 'Windows': # On Windows we need to examine the resource section of the binary import winreg def _read_registry(root, key, value): try: hkey = winreg.OpenKey(root, key) except Exception as e: return None try: (val, typ) = winreg.QueryValueEx(hkey, value) except Exception as e: winreg.CloseKey(hkey) return None winreg.CloseKey(hkey) return val key = r'SOFTWARE\Google\Chrome\BLBeacon' version_str = _read_registry(winreg.HKEY_CURRENT_USER, key, 'Version') # On a 64b host, look for a 32b installation if not version_str: key = r'SOFTWARE\Wow6432Node\Google\Chrome\BLBeacon' version_str = _read_registry(winreg.HKEY_CURRENT_USER, key, 'Version') if not version_str: print('The Chrome version could not be read from the registry.') sys.exit(1) chrome_version = '.'.join(version_str.split()[-1].split('.')[:-1]) else: # On Linux/Mac we run the Chrome executable with the --version flag, # then parse the output. try: result = subprocess.Popen([args.chrome, '--version'], stdout=subprocess.PIPE) except FileNotFoundError: print('The specified Chrome executable could not be found.') sys.exit(1) version_str = result.stdout.read().decode("utf-8") # Check for 'Chrom' not 'Chrome' in case the user is using Chromium. if "Chrom" not in version_str: print('The specified Chrome executable output an unexpected ' 'version string: {}.'.format(version_str)) sys.exit(1) # On some linux distro `chrome--version` gives output like # 'Google Chrome 80.0.3987.132 unknown\n' # so we need to check and remove the unknown string from the version if version_str.endswith("unknown\n"): version_str = version_str.strip("unknown\n").strip() chrome_version = '.'.join(version_str.split()[-1].split('.')[:-1]) if chrome_version.count('.') != 2: print('The specified Chrome executable output an unexpected ' 'version string: {}.'.format(version_str)) sys.exit(1) return chrome_version def get_chromedriver_version(chrome_version): """Get the required chromedriver version number. Args: chrome_version: The chrome version number Returns: The chromedriver version number """ url = 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_{}' \ .format(chrome_version) try: fp = urlopen(url) except URLError as e: print('The chromedriver catalog URL could not be accessed: {}' .format(e)) sys.exit(1) version = fp.read().decode("utf-8").strip() fp.close() return version def get_system(): """Get the system name as known to chromedriver Returns: The system name """ if platform.system() == 'Darwin': return 'mac64' elif platform.system() == 'Linux': return 'linux64' elif platform.system() == 'Windows': return 'win32' else: print("Unknown or unsupported operating system: {}" .format(platform.system())) sys.exit(1) """The core structure of the app.""" # Read the command line options args = read_command_line() chrome_version = get_chrome_version(args) # Check the directory exists if not os.path.isdir(args.directory): print('The specified output directory could not be accessed.') sys.exit(1) chromedriver_version = get_chromedriver_version(chrome_version) system = get_system() url = 'https://chromedriver.storage.googleapis.com/{}/chromedriver_{}.zip' \ .format(chromedriver_version, system) print('Downloading chromedriver v{} for Chrome v{} on {}...' .format(chromedriver_version, chrome_version, system)) try: file, headers = urlretrieve(url) except URLError as e: print('The chromedriver download URL could not be accessed: {}' .format(e)) sys.exit(1) # Unzip chromedriver print('Extracting chromedriver...') found = False fp = open(file, 'rb') z = zipfile.ZipFile(fp) for name in z.namelist(): if (system == 'win32' and name == 'chromedriver.exe') or \ (system != 'win32' and name == 'chromedriver'): z.extract(name, args.directory) found = True fp.close() if not found: print("chromedriver could not be found in the downloaded archive: {}" .format(file)) sys.exit(1) # Set the permissions if system == 'mac64' or system == 'linux64': os.chmod(os.path.join(args.directory, 'chromedriver'), 0o755) print('Chromedriver downloaded to: {}'.format(args.directory))