Esempio n. 1
0
def get_python(config: Config) -> Python:
    """Get prefered Python.

    Lookup order:

    1. Defined in config.
    2. Defined in dependencies file.
    3. Current active Python.

    Use it when you want to create new venv.
    """
    pythons = Pythons()

    # defined in config
    python = config.get('python')
    if python:
        return pythons.get_best(python)

    # defined in dependencies file
    if 'from' in config:
        loader = CONVERTERS[config['from']['format']]
        root = loader.load(path=config['from']['path'])
        if root.python:
            return pythons.get_by_spec(root.python)

    return pythons.current
Esempio n. 2
0
    def __call__(self) -> bool:
        # load project
        loader = CONVERTERS[self.config['from']['format']]
        loader = loader.copy(project_path=Path(self.config['project']))
        resolver = loader.load_resolver(path=self.config['from']['path'])
        if loader.lock:
            self.logger.warning('do not build project from lockfile!')

        # attach
        merged = attach_deps(resolver=resolver, config=self.config, merge=True)
        if not merged:
            conflict = analyze_conflict(resolver=resolver)
            self.logger.warning('conflict was found')
            print(conflict)
            return False

        # dump
        project_path = Path(self.config['project'])
        reqs = Requirement.from_graph(resolver.graph, lock=False)
        self.logger.info('creating wheel...')
        dumper = WheelConverter()
        project = resolver.graph.metainfo
        dumper.dump(path=project_path / 'dist', reqs=reqs, project=project)
        wheel_path = dumper._get_path(path=project_path / 'dist',
                                      project=project)

        # get command
        command = self.args.name
        if not command:
            command = self.config.get('command')
            if not command:
                self.logger.error('command required')
                return False
        if isinstance(command, str):
            command = shlex.split(command)

        # choose pythons
        self.logger.info('get interpreters')
        pythons = Pythons()
        choosen_pythons: Tuple[Python, ...]
        if 'python' in self.config:
            # get from config
            choosen_pythons = (pythons.get_best(self.config['python']), )
        else:
            # get from project
            pythons_by_version = dict()  # type: Dict[str, Python]
            python_constraint = resolver.graph.metainfo.python
            for python in pythons:
                version = str(python.get_short_version())
                if version in pythons_by_version:
                    continue
                if python.version not in python_constraint:
                    continue
                pythons_by_version[version] = python
            choosen_pythons = tuple(pythons_by_version.values())

        for python in choosen_pythons:
            with TemporaryDirectory(
            ) as root_path:  # type: Path # type: ignore
                root_path = Path(root_path)

                # make venv
                self.logger.info('create venv',
                                 extra=dict(python=str(python.version)))
                venv = VEnv(path=root_path / 'venv')
                venv.create(python_path=python.path)

                # copy tests
                for path in self.config['tests']:  # type: Path
                    self.logger.info('copy files', extra=dict(path=path))
                    path = Path(path)
                    if not path.exists():
                        raise FileNotFoundError(str(path))

                    # copy file
                    if path.is_file():
                        shutil.copyfile(str(path), str(root_path / path.name))
                        continue

                    # copy dir
                    for subpath in path.glob('**/*'):
                        if not subpath.is_file():
                            continue
                        if '__pycache__' in subpath.parts:
                            continue
                        new_path = subpath.resolve().relative_to(
                            self.config['project'])
                        new_path = root_path.joinpath(new_path)
                        self.logger.debug('copy',
                                          extra=dict(old=str(subpath),
                                                     new=str(new_path)))
                        new_path.parent.mkdir(exist_ok=True, parents=True)
                        shutil.copyfile(str(subpath), str(new_path))

                # install project
                self.logger.info('install project',
                                 extra=dict(path=str(wheel_path)))
                dep_spec = str(wheel_path)
                extras = set(self.config.get('envs', [])) - {'main'}
                if extras:
                    dep_spec += '[{}]'.format(','.join(extras))
                # we are using pip here to make it closer to the real installation
                result = subprocess.run(
                    [str(venv.bin_path / 'pip'), 'install', dep_spec],
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                )
                if result.returncode != 0:
                    self.logger.error('failed to install project')
                    self.logger.error(result.stderr.decode())
                    return False

                # install executable
                executable = venv.bin_path / command[0]
                if not executable.exists():
                    self.logger.info('executable not found, installing',
                                     extra=dict(executable=command[0], ))
                    result = subprocess.run(
                        [str(venv.bin_path / 'pip'), 'install', command[0]],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                    )
                    if result.returncode != 0:
                        self.logger.error('failed to install tests executable')
                        self.logger.error(result.stderr.decode())
                        return False

                # run tests
                self.logger.info('run tests', extra=dict(command=command))
                result = subprocess.run(
                    [str(executable)] + command[1:],
                    cwd=str(root_path),
                )
                if result.returncode != 0:
                    self.logger.error('command failed, stopping')
                    return False

        return True