예제 #1
0
def test_get_python_executable_from_pyinstaller():

    try:
        setattr(sys, '_MEIPASS', 'mock')
        with pytest.raises(RuntimeError) as e:
            utils.get_python_executable('python')
        assert 'Executables are not supported' in str(e)
    finally:
        delattr(sys, '_MEIPASS')
예제 #2
0
def test_get_python_executable_from_pyinstaller_with_exec_host():

    try:
        setattr(sys, '_MEIPASS', 'mock')
        python_path = utils.get_python_executable('python',
                                                  exec_home=sys.exec_prefix)
        assert os.path.abspath(sys.exec_prefix) in python_path
    finally:
        delattr(sys, '_MEIPASS')
예제 #3
0
def test_set_version(github, temp_dir, runner):

    expected_version = '0.0.3'
    result = github.run('set-version --branch release --value {}'.format(expected_version))

    setup_py = github.api.repo.get_contents(path='setup.py', ref='heads/release').decoded_content
    setup_py_path = os.path.join(temp_dir, 'setup.py')
    with open(setup_py_path, 'wb') as stream:
        stream.write(setup_py)

    actual_version = runner.run('{} {} --version'.format(utils.get_python_executable('python'),
                                                         setup_py_path)).std_out

    expected_output = 'Version is now {} (was 0.0.1)'.format(expected_version)

    assert expected_output in result.std_out
    assert expected_version == actual_version
예제 #4
0
def test_bump_version(github, temp_dir, runner):

    result = github.run('bump-version --branch release --semantic patch')

    expected_version = '0.0.2'
    expected_output = 'Bumped version from 0.0.1 to {}'.format(expected_version)

    setup_py = github.api.repo.get_contents(path='setup.py', ref='heads/release').decoded_content
    setup_py_path = os.path.join(temp_dir, 'setup.py')
    with open(setup_py_path, 'wb') as stream:
        stream.write(setup_py)

    actual_version = runner.run('{} {} --version'.format(utils.get_python_executable('python'),
                                                         setup_py_path)).std_out

    assert expected_output in result.std_out
    assert expected_version == actual_version
예제 #5
0
    def _lookup_interpreter(self):
        if utils.is_pyinstaller():
            self._debug(
                'Running inside a frozen package...Looking up python interpreter from PATH'
            )
            interpreter = utils.which('python')
        else:
            self._debug(
                'Running inside a python environment...Looking up python interpreter locally'
            )
            interpreter = utils.get_python_executable('python')

        if not interpreter:
            raise exceptions.PythonNotFoundException()

        self._debug('Python interpreter: {}'.format(interpreter))

        return interpreter
예제 #6
0
    def _create_virtualenv(self, name):

        temp_dir = tempfile.mkdtemp()

        virtualenv_path = os.path.join(temp_dir, name)

        self._debug('Creating virtualenv {}'.format(virtualenv_path))

        def _create_virtualenv_dist():

            dist_directory = os.path.join(temp_dir, 'virtualenv-dist')
            support_directory = os.path.join(dist_directory,
                                             'virtualenv_support')

            os.makedirs(dist_directory)
            os.makedirs(support_directory)

            _virtualenv_py = os.path.join(dist_directory, 'virtualenv.py')

            def _write_support_wheel(_wheel):

                with open(os.path.join(support_directory, _wheel), 'wb') as _w:
                    _w.write(
                        get_binary_resource(
                            os.path.join('virtualenv_support', _wheel)))

            with open(_virtualenv_py, 'w') as venv_py:
                venv_py.write(get_text_resource('virtualenv.py'))

            _write_support_wheel('pip-19.1.1-py2.py3-none-any.whl')
            _write_support_wheel('setuptools-41.0.1-py2.py3-none-any.whl')

            return _virtualenv_py

        virtualenv_py = _create_virtualenv_dist()

        create_virtualenv_command = '{} {} --no-wheel {}'.format(
            self._interpreter, virtualenv_py, virtualenv_path)

        requirements_file = os.path.join(self._repo_dir, 'requirements.txt')

        self._runner.run(create_virtualenv_command, cwd=self._repo_dir)

        pip_path = utils.get_python_executable('pip',
                                               exec_home=virtualenv_path)

        install_command = None

        if os.path.exists(requirements_file):

            self._debug(
                'Using requirements file: {}'.format(requirements_file))
            install_command = '{} -r {}'.format(self._pip_install(pip_path),
                                                requirements_file)

        elif os.path.exists(self._setup_py_path):

            self._debug('Using install_requires from setup.py: {}'.format(
                self._setup_py_path))
            requires = self._setup_py.get('install_requires')
            install_command = '{} {}'.format(self._pip_install(pip_path),
                                             ' '.join(requires))

        if install_command:
            self._debug('Installing {} requirements...'.format(name))
            self._runner.run(install_command, cwd=self._repo_dir)

        self._debug(
            'Successfully created virtualenv {}'.format(virtualenv_path))

        try:
            yield virtualenv_path
        finally:
            try:
                utils.rmf(temp_dir)
            except BaseException as e:
                if utils.is_windows():
                    # The temp_dir was populated with files written by a different process
                    # (pip install) On windows, this causes a [Error 5] Access is denied error.
                    # Eventually I will have to fix this - until then, sorry windows users...
                    self._debug(
                        "Failed cleaning up temporary directory after creating virtualenv "
                        "{}: {} - You might have some leftovers because of this..."
                        .format(temp_dir, str(e)))
                else:
                    raise
예제 #7
0
    def wheel(self, universal=False, wheel_version=None):
        """
        Create a wheel package.

        This method will create a wheel package, according the the regular python wheel standards.

        Under the hood, this uses the bdist_wheel command provided by the wheel project.

        For more information please visit https://pythonwheels.com/

        Args:
            universal (:bool, optional): True if the created will should be universal, False otherwise.
            wheel_version (:str, optional): Which wheel version to use.

        Raises:
            WheelExistsException: Destination file already exists.
            DirectoryDoesntExistException: Destination directory does not exist.

        """

        temp_dir = tempfile.mkdtemp()
        try:

            dist_dir = os.path.join(temp_dir, 'dist')
            bdist_dir = os.path.join(temp_dir, 'bdist')

            if not os.path.exists(self._setup_py_path):
                raise exceptions.SetupPyNotFoundException(
                    repo=self._repo_location)

            name = self._name

            with self._create_virtualenv(name) as virtualenv:

                self._logger.debug('Installing wheel...')

                pip_path = utils.get_python_executable('pip',
                                                       exec_home=virtualenv)
                self._runner.run('{} wheel=={}'.format(
                    self._pip_install(pip_path), wheel_version
                    or DEFAULT_WHEEL_VERSION),
                                 cwd=self._repo_dir)

                command = '{} {} bdist_wheel --bdist-dir {} --dist-dir {}'.format(
                    utils.get_python_executable('python',
                                                exec_home=virtualenv),
                    self._setup_py_path, bdist_dir, dist_dir)

                if universal:
                    command = '{0} --universal'.format(command)

                self._debug('Running bdist_wheel...', universal=universal)

                self._runner.run(command, cwd=self._repo_dir)

            self._debug('Finished running bdist_wheel.', universal=universal)

            actual_name = utils.lsf(dist_dir)[0]

            destination = os.path.join(self._target_dir, actual_name)

            try:
                utils.validate_file_does_not_exist(path=destination)
            except exceptions.FileExistException as e:
                raise exceptions.WheelExistsException(path=e.path)

            shutil.copy(os.path.join(dist_dir, actual_name), destination)
            self._debug('Packaged successfully.', package=destination)
            return os.path.abspath(destination)

        finally:
            utils.rmf(temp_dir)
예제 #8
0
    def binary(self,
               base_name=None,
               entrypoint=None,
               pyinstaller_version=None):
        """
        Create a binary executable.

        This method will create a self-contained, platform dependent, executable file.

        Under the hood, this uses the PyInstaller project.

        For more information please visit https://www.pyinstaller.org/

        Args:

            base_name (:str, optional):

                The base name of the target file. The final name will be in the
                form of: <name>-<platform-machine>-<platform-system> (e.g pyci-x86_64-Darwin).
                Defaults to the 'name' specified in your setup.py file.

            entrypoint (:str, optional):

                Path to a script file from which the executable
                is built. This can either by a .py or a .spec file.
                By default, the packager will look for the entry point specified in setup.py.

            pyinstaller_version (:str, optional):

                Which PyInstaller version to use. Defaults to 3.4.

        Raises:

            BinaryExistsException:

                Destination file already exists.

            DirectoryDoesntExistException:

                Destination directory does not exist.

            DefaultEntrypointNotFoundException:

                A custom entrypoint is not provided and the default entry-points
                pyci looks for are also missing.

            EntrypointNotFoundException:

                The provided custom entrypoint provided does not exist in the repository.

            MultipleDefaultEntrypointsFoundException:

                If setup.py contains multiple entrypoints specification.

        """

        temp_dir = tempfile.mkdtemp()
        try:

            base_name = base_name or self._name
            entrypoint = entrypoint or self._entrypoint

            destination = os.path.join(
                self._target_dir, '{0}-{1}-{2}'.format(base_name,
                                                       platform.machine(),
                                                       platform.system()))

            if platform.system().lower() == 'windows':
                destination = '{0}.exe'.format(destination)

            try:
                utils.validate_file_does_not_exist(path=destination)
            except exceptions.FileExistException as e:
                raise exceptions.BinaryExistsException(path=e.path)

            dist_dir = os.path.join(temp_dir, 'dist')
            build_dir = os.path.join(temp_dir, 'build')

            script = os.path.join(self._repo_dir, entrypoint)

            if not os.path.exists(script):
                raise exceptions.EntrypointNotFoundException(
                    repo=self._repo_location, entrypoint=entrypoint)

            with self._create_virtualenv(base_name) as virtualenv:

                self._logger.debug('Installing pyinstaller...')

                pip_path = utils.get_python_executable('pip',
                                                       exec_home=virtualenv)
                self._runner.run('{} pyinstaller=={}'.format(
                    self._pip_install(pip_path), pyinstaller_version
                    or DEFAULT_PY_INSTALLER_VERSION),
                                 cwd=self._repo_dir)

                self._debug('Running pyinstaller...',
                            entrypoint=entrypoint,
                            destination=destination)
                pyinstaller_path = utils.get_python_executable(
                    'pyinstaller', exec_home=virtualenv)
                self._runner.run('{} '
                                 '--onefile '
                                 '--distpath {} '
                                 '--workpath {} '
                                 '--specpath {} {}'.format(
                                     self._pyinstaller(pyinstaller_path),
                                     dist_dir, build_dir, temp_dir, script))

                self._debug('Finished running pyinstaller',
                            entrypoint=entrypoint,
                            destination=destination)

            actual_name = utils.lsf(dist_dir)[0]

            package_path = os.path.join(dist_dir, actual_name)
            self._debug('Copying package to destination...',
                        src=package_path,
                        dst=destination)
            shutil.copy(package_path, destination)

            self._debug('Packaged successfully.', package=destination)
            return os.path.abspath(destination)
        finally:
            utils.rmf(temp_dir)
예제 #9
0
def test_get_python_executable():

    python_path = utils.get_python_executable('python')

    assert os.path.abspath(sys.exec_prefix) in python_path