Beispiel #1
0
    def install(self) -> int:
        venv = VEnv(path=self.path)
        if not venv.exists():
            print('creating venv...', file=self.stream)
            venv.create()

        bin_path = venv.bin_path
        assert bin_path
        if not (bin_path / 'wheel').exists():
            print('installing wheel...', file=self.stream)
            self._pip_install('pip', 'wheel', 'setuptools')
        constr = self.root / 'requirements.txt'
        if constr.exists():
            print('installing requirements.txt...', file=self.stream)
            self._pip_install('-r', str(constr))

        try:
            print('installing project deps...', file=self.stream)
            flit.main([
                'install',
                '--python',
                str(venv.python_path),
                '--deps',
                'production',
                '--extras',
                self.name,
                '--symlink',
            ])
        except SystemExit as exc:
            return exc.code
        return 0
Beispiel #2
0
def test_deps_audit_command(temp_path: Path, capsys):
    reqs_path = temp_path / 'requirements.txt'
    reqs_path.write_text('six==1.12.0')

    venv_path = temp_path / 'venv'
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'level': 'WARNING',
        'silent': True,
        'nocolors': True,
    })

    command = DepsAuditCommand(argv=['jinja2==2.0'], config=config)
    result = command()

    captured = capsys.readouterr()
    print(captured.err)
    print(captured.out)
    assert result is False
    output = json.loads(captured.out)
    assert len(output) >= 2
    for entry in output:
        assert entry['current'] == '2.0'
        assert entry['name'] == 'jinja2'
Beispiel #3
0
def test_package_install_command(temp_path: Path):
    venv_path = temp_path / 'venv'
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'project': str(temp_path),
        'venv': str(venv_path),
    })

    command = PackageInstallCommand(argv=['six==1.12.0'], config=config)
    result = command()

    assert result is True
    assert (venv.lib_path / 'six-1.12.0.dist-info' / 'METADATA').exists()
def test_inspect_venv_command(temp_path: Path, capsys):
    venv = VEnv(path=temp_path)
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'project': str(temp_path),
        'venv': str(temp_path),
    })

    command = InspectVenvCommand(argv=[], config=config)
    result = command()
    assert result is True

    captured = capsys.readouterr()
    output = json.loads(captured.out)
    assert output['exists'] is True
    assert output['bin'] == str(venv.bin_path)
Beispiel #5
0
def test_venv_destroy_command(temp_path: Path):
    venv_path = temp_path / 'venv'
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'project': str(temp_path),
        'venv': str(venv_path),
    })

    command = VenvDestroyCommand(argv=[], config=config)
    result = command()

    assert result is True
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
Beispiel #6
0
def test_create(temp_path):
    venv = VEnv(path=temp_path)
    assert venv.exists() is False
    assert venv.lib_path is None
    assert venv.bin_path is None
    assert venv.python_path is None

    venv.create()

    assert venv.exists() is True
    assert venv.lib_path.exists()
    assert venv.bin_path.exists()
    assert (venv.bin_path / 'pip').exists() or (venv.bin_path /
                                                'pip.exe').exists()
    assert venv.python_path.exists()

    venv.destroy()
    assert venv.exists() is False
Beispiel #7
0
def test_deps_install_command(temp_path: Path):
    reqs_path = temp_path / 'requirements.txt'
    reqs_path.write_text('six==1.12.0')

    venv_path = temp_path / 'venv'
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'from': dict(format='pip', path=str(reqs_path)),
        'project': str(temp_path),
        'venv': str(venv_path),
    })

    command = DepsInstallCommand(argv=[], config=config)
    result = command()

    assert result is True
    assert (venv.lib_path / 'six-1.12.0.dist-info' / 'METADATA').exists()
Beispiel #8
0
def test_deps_outdated_command_venv(temp_path: Path, capsys):
    venv_path = temp_path / 'venv'
    venv = VEnv(path=venv_path)
    assert venv.exists() is False
    venv.create(python_path=sys.executable)

    config = Config()
    config.attach({
        'project': str(temp_path),
        'venv': str(venv_path),
        'level': 'WARNING',
        'silent': True,
    })

    command = DepsOutdatedCommand(argv=[], config=config)
    result = command()

    assert type(result) is bool
    if result is False:
        captured = capsys.readouterr()
        output = json.loads(captured.out)
        names = {line['name'] for line in output}
        assert len(names - {'pip', 'setuptools'}) == 0
Beispiel #9
0
    def __call__(self) -> bool:
        resolver = get_resolver(reqs=self.args.name)
        name = next(iter(resolver.graph.get_layer(0))).dependencies[0].name

        command = self.config.get('command')
        if not command:
            command = 'python'
        if isinstance(command, str):
            command = shlex.split(command)

        with TemporaryDirectory() as base_path:
            base_path = Path(base_path)

            # make venv
            venv = VEnv(path=base_path)
            if venv.exists():
                self.logger.error('already installed', extra=dict(package=name))
                return False
            python = get_python(self.config)
            self.logger.info('creating venv...', extra=dict(
                venv=str(venv.path),
                python=str(python.path),
            ))
            venv.create(python_path=python.path)

            # install
            ok = install_deps(
                resolver=resolver,
                python_path=venv.python_path,
                logger=self.logger,
                silent=self.config['silent'],
            )
            if not ok:
                return False

            # install executable
            executable = venv.bin_path / command[0]
            if not executable.exists():
                self.logger.warning('executable is not found in venv, trying to install...', extra=dict(
                    executable=command[0],
                ))
                ok = install_dep(
                    name=command[0],
                    python_path=venv.python_path,
                    logger=self.logger,
                    silent=self.config['silent'],
                )
                if not ok:
                    return False
            if not executable.exists():
                self.logger.error('package installed, but executable is not found')
                return False

            # make startup script to import installed packages
            startup_path = base_path / '_startup.py'
            packages = self._get_startup_packages(lib_path=venv.lib_path, packages=self.args.name)
            if not packages:
                self.logger.error('cannot find any packages')
                return False
            startup_path.write_text('import ' + ', '.join(sorted(packages)))

            # run
            self.logger.info('running...')
            with override_env_vars({'PYTHONSTARTUP': str(startup_path)}):
                result = subprocess.run([str(executable)] + command[1:])
            if result.returncode != 0:
                self.logger.error('command failed', extra=dict(code=result.returncode))
                return False

            return True
Beispiel #10
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