def _verify_pip_is_installed(): """Verify that pip is installed. Raises: ImportError. Error importing pip. """ try: python_utils.PRINT('Checking if pip is installed on the local machine') # Importing pip just to check if its installed. import pip #pylint: disable=unused-variable except ImportError as e: common.print_each_string_after_two_new_lines([ 'Pip is required to install Oppia dependencies, but pip wasn\'t ' 'found on your local machine.', 'Please see \'Installing Oppia\' on the Oppia developers\' wiki ' 'page:']) if common.is_mac_os(): python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28Mac-' 'OS%29') elif common.is_linux_os(): python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28Linux' '%29') else: python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28' 'Windows%29') raise ImportError('Error importing pip: %s' % e)
def create_managed_web_browser(port): """Returns a context manager for a web browser targeting the given port on localhost. If a web browser cannot be opened on the current system by Oppia, then returns None instead. Args: port: int. The port number to open in the web browser. Returns: context manager|None. The context manager to a web browser window, or None if the current operating system does not support web browsers. """ url = 'http://localhost:%s/' % port human_readable_name = 'Web Browser' if common.is_linux_os(): if any(re.match('.*VBOX.*', d) for d in os.listdir('/dev/disk/by-id/')): return None else: return managed_process( ['xdg-open', url], human_readable_name=human_readable_name) elif common.is_mac_os(): return managed_process( ['open', url], human_readable_name=human_readable_name) else: return None
def get_chrome_driver_version(): """Fetches the latest supported version of chromedriver depending on the Chrome version. This method follows the steps mentioned here: https://chromedriver.chromium.org/downloads/version-selection """ popen_args = ['google-chrome', '--version'] if common.is_mac_os(): # There are spaces between Google and Chrome in the path. Spaces don't # need to be escaped when we're not using the terminal, ie. shell=False # for Popen by default. popen_args = [ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', '--version' ] try: proc = subprocess.Popen(popen_args, stdout=subprocess.PIPE) output = proc.stdout.readline() except OSError: # For the error message for the mac command, we need to add the # backslashes in. This is because it is likely that a user will try to # run the command on their terminal and, as mentioned above, the mac # get chrome version command has spaces in the path which need to be # escaped for successful terminal use. raise Exception( 'Failed to execute "%s" command. ' 'This is used to determine the chromedriver version to use. ' 'Please set the chromedriver version manually using ' '--chrome_driver_version flag. To determine the chromedriver ' 'version to be used, please follow the instructions mentioned ' 'in the following URL:\n' 'https://chromedriver.chromium.org/downloads/version-selection' % ( ' '.join(arg.replace(' ', r'\ ') for arg in popen_args) ) ) chrome_version = ''.join(re.findall(r'([0-9]|\.)', output)) chrome_version = '.'.join(chrome_version.split('.')[:-1]) response = python_utils.url_open( 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s' % chrome_version) chrome_driver_version = response.read() python_utils.PRINT('\n\nCHROME VERSION: %s' % chrome_version) return chrome_driver_version
def verify_pip_is_installed(): """Verify that pip is installed. Raises: ImportError. Error importing pip. """ python_utils.PRINT('Checking if pip is installed on the local machine') try: import pip except ImportError as e: common.print_each_string_after_two_new_lines([ 'Pip is required to install Oppia dependencies, but pip wasn\'t ' 'found on your local machine.', 'Please see \'Installing Oppia\' on the Oppia developers\' wiki ' 'page:' ]) if common.is_mac_os(): python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28Mac-' 'OS%29') elif common.is_linux_os(): python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28Linux' '%29') else: python_utils.PRINT( 'https://github.com/oppia/oppia/wiki/Installing-Oppia-%28' 'Windows%29') raise ImportError('Error importing pip: %s' % e) else: if pip.__version__ != OPPIA_REQUIRED_PIP_VERSION: common.print_each_string_after_two_new_lines([ 'Oppia requires pip==%s, but you have pip==%s installed.' % (OPPIA_REQUIRED_PIP_VERSION, pip.__version__), 'Upgrading pip on your behalf...', ]) _run_pip_command( ['install', 'pip==%s' % OPPIA_REQUIRED_PIP_VERSION])
def managed_webdriver_server(chrome_version=None): """Returns context manager to start/stop the Webdriver server gracefully. This context manager updates Google Chrome before starting the server. Args: chrome_version: str|None. The version of Google Chrome to run the tests on. If None, then the currently-installed version of Google Chrome is used instead. Yields: psutil.Process. The Webdriver process. """ if chrome_version is None: # Although there are spaces between Google and Chrome in the path, we # don't need to escape them for Popen (as opposed to on the terminal, in # which case we would need to escape them for the command to run). chrome_command = ( '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' if common.is_mac_os() else 'google-chrome') try: output = subprocess.check_output([chrome_command, '--version']) except OSError: # For the error message on macOS, we need to add the backslashes in. # This is because it is likely that a user will try to run the # command on their terminal and, as mentioned above, the macOS # chrome version command has spaces in the path which need to be # escaped for successful terminal use. raise Exception( 'Failed to execute "%s --version" command. This is used to ' 'determine the chromedriver version to use. Please set the ' 'chromedriver version manually using the ' '--chrome_driver_version flag. To determine the ' 'chromedriver version to be used, please follow the ' 'instructions mentioned in the following URL:\n' 'https://chromedriver.chromium.org/downloads/version-selection' % chrome_command.replace(' ', r'\ ')) installed_version_parts = b''.join(re.findall(rb'[0-9.]', output)) installed_version = '.'.join( installed_version_parts.decode('utf-8').split('.')[:-1]) response = utils.url_open( 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s' % ( installed_version)) chrome_version = response.read().decode('utf-8') print('\n\nCHROME VERSION: %s' % chrome_version) subprocess.check_call([ common.NODE_BIN_PATH, common.WEBDRIVER_MANAGER_BIN_PATH, 'update', '--versions.chrome', chrome_version, ]) with contextlib.ExitStack() as exit_stack: if common.is_windows_os(): # NOTE: webdriver-manager (version 13.0.0) uses `os.arch()` to # determine the architecture of the operating system, however, this # function can only be used to determine the architecture of the # machine that compiled `node`. In the case of Windows, we are using # the portable version, which was compiled on `ia32` machine so that # is the value returned by this `os.arch` function. Unfortunately, # webdriver-manager seems to assume that Windows wouldn't run on the # ia32 architecture, so its help function used to determine download # link returns null for this, which means that the application has # no idea about where to download the correct version. # # https://github.com/angular/webdriver-manager/blob/b7539a5a3897a8a76abae7245f0de8175718b142/lib/provider/chromedriver.ts#L16 # https://github.com/angular/webdriver-manager/blob/b7539a5a3897a8a76abae7245f0de8175718b142/lib/provider/geckodriver.ts#L21 # https://github.com/angular/webdriver-manager/blob/b7539a5a3897a8a76abae7245f0de8175718b142/lib/provider/chromedriver.ts#L167 # https://github.com/nodejs/node/issues/17036 regex_pattern = re.escape('this.osArch = os.arch();') arch = 'x64' if common.is_x64_architecture() else 'x86' replacement_string = 'this.osArch = "%s";' % arch exit_stack.enter_context(common.inplace_replace_file_context( common.CHROME_PROVIDER_FILE_PATH, regex_pattern, replacement_string)) exit_stack.enter_context(common.inplace_replace_file_context( common.GECKO_PROVIDER_FILE_PATH, regex_pattern, replacement_string)) # OK to use shell=True here because we are passing string literals and # constants, so there is no risk of a shell-injection attack. proc = exit_stack.enter_context(managed_process([ common.NODE_BIN_PATH, common.WEBDRIVER_MANAGER_BIN_PATH, 'start', '--versions.chrome', chrome_version, '--quiet', '--standalone', ], human_readable_name='Webdriver manager', shell=True)) common.wait_for_port_to_be_in_use(4444) yield proc