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
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