Пример #1
0
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)
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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])
Пример #5
0
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