def load(cls, env): # type: (Env) -> InstalledRepository """ Load installed packages. For now, it uses the pip "freeze" command. """ repo = cls() freeze_output = env.run_pip("freeze") for line in freeze_output.split("\n"): if "==" in line: name, version = re.split("={2,3}", line) repo.add_package(Package(name, version, version)) elif line.startswith("-e "): line = line[3:].strip() if line.startswith("git+"): url = line.lstrip("git+") if "@" in url: url, rev = url.rsplit("@", 1) else: rev = "master" name = url.split("/")[-1].rstrip(".git") if "#egg=" in rev: rev, name = rev.split("#egg=") package = Package(name, "0.0.0") package.source_type = "git" package.source_url = url package.source_reference = rev repo.add_package(package) return repo
def find_packages(self, name, constraint=None, extras=None, allow_prereleases=False): packages = [] if constraint is None: constraint = "*" if not isinstance(constraint, VersionConstraint): constraint = parse_constraint(constraint) if isinstance(constraint, VersionRange): if (constraint.max is not None and constraint.max.is_prerelease() or constraint.min is not None and constraint.min.is_prerelease()): allow_prereleases = True key = name if not constraint.is_any(): key = "{}:{}".format(key, str(constraint)) if self._cache.store("matches").has(key): versions = self._cache.store("matches").get(key) else: page = self._get("/{}/".format( canonicalize_name(name).replace(".", "-"))) if page is None: return [] versions = [] for version in page.versions: if version.is_prerelease() and not allow_prereleases: continue if constraint.allows(version): versions.append(version) self._cache.store("matches").put(key, versions, 5) for version in versions: package = Package(name, version) package.source_type = "legacy" package.source_reference = self.name package.source_url = self._url if extras is not None: package.requires_extras = extras packages.append(package) self._log( "{} packages found for {} {}".format(len(packages), name, str(constraint)), level="debug", ) return packages
def load(cls, env): # type: (Env) -> InstalledRepository """ Load installed packages. For now, it uses the pip "freeze" command. """ repo = cls() seen = set() for entry in env.sys_path: for distribution in sorted( metadata.distributions(path=[entry]), key=lambda d: str(d._path), ): name = distribution.metadata["name"] version = distribution.metadata["version"] package = Package(name, version, version) package.description = distribution.metadata.get("summary", "") if package.name in seen: continue seen.add(package.name) repo.add_package(package) path = Path(str(distribution._path)) is_standard_package = True try: path.relative_to(env.site_packages) except ValueError: is_standard_package = False if is_standard_package: continue src_path = env.path / "src" # A VCS dependency should have been installed # in the src directory. If not, it's a path dependency try: path.relative_to(src_path) from poetry.vcs.git import Git git = Git() revision = git.rev_parse("HEAD", src_path / package.name).strip() url = git.remote_url(src_path / package.name) package.source_type = "git" package.source_url = url package.source_reference = revision except ValueError: package.source_type = "directory" package.source_url = str(path.parent) return repo
def search_for_file(self, dependency): # type: (FileDependency) -> List[Package] package = Package(dependency.name, dependency.pretty_constraint) package.source_type = 'file' package.source_reference = str(dependency.path) package.description = dependency.metadata.summary for req in dependency.metadata.requires_dist: package.requires.append(dependency_from_pep_508(req)) if dependency.metadata.requires_python: package.python_versions = dependency.metadata.requires_python if dependency.metadata.platforms: package.platform = ' || '.join(dependency.metadata.platforms) package.hashes = [dependency.hash()] return [package]
def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package] """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency.vcs != "git": raise ValueError("Unsupported VCS dependency {}".format( dependency.vcs)) tmp_dir = Path( mkdtemp(prefix="pypoetry-git-{}".format(dependency.name))) try: git = Git() git.clone(dependency.source, tmp_dir) git.checkout(dependency.reference, tmp_dir) revision = git.rev_parse(dependency.reference, tmp_dir).strip() if dependency.tag or dependency.rev: revision = dependency.reference pyproject = TomlFile(tmp_dir / "pyproject.toml") pyproject_content = None has_poetry = False if pyproject.exists(): pyproject_content = pyproject.read() has_poetry = ("tool" in pyproject_content and "poetry" in pyproject_content["tool"]) if pyproject_content and has_poetry: # If a pyproject.toml file exists # We use it to get the information we need info = pyproject_content["tool"]["poetry"] name = info["name"] version = info["version"] package = Package(name, version, version) package.source_type = dependency.vcs package.source_url = dependency.source package.source_reference = dependency.reference for req_name, req_constraint in info["dependencies"].items(): if req_name == "python": package.python_versions = req_constraint continue package.add_dependency(req_name, req_constraint) else: # We need to use setup.py here # to figure the information we need # We need to place ourselves in the proper # folder for it to work venv = Venv.create(self._io) current_dir = os.getcwd() os.chdir(tmp_dir.as_posix()) try: venv.run("python", "setup.py", "egg_info") # Sometimes pathlib will fail on recursive # symbolic links, so we need to workaround it # and use the glob module instead. # Note that this does not happen with pathlib2 # so it's safe to use it for Python < 3.4. if PY35: egg_info = next( Path(p) for p in glob.glob( os.path.join(str(tmp_dir), "**", "*.egg-info"), recursive=True, )) else: egg_info = next(tmp_dir.glob("**/*.egg-info")) meta = pkginfo.UnpackedSDist(str(egg_info)) if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / "requires.txt" if requires.exists(): with requires.open() as f: reqs = parse_requires(f.read()) package = Package(meta.name, meta.version) for req in reqs: dep = dependency_from_pep_508(req) if dep.in_extras: for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) package.requires.append(dep) except Exception: raise finally: os.chdir(current_dir) package.source_type = "git" package.source_url = dependency.source package.source_reference = revision except Exception: raise finally: shutil.rmtree(tmp_dir.as_posix()) if dependency.name != package.name: # For now, the dependency's name must match the actual package's name raise RuntimeError( "The dependency name for {} does not match the actual package's name: {}" .format(dependency.name, package.name)) if dependency.extras: for extra in dependency.extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() return [package]
def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package] """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency.vcs != 'git': raise ValueError('Unsupported VCS dependency {}'.format( dependency.vcs)) tmp_dir = Path( mkdtemp(prefix='pypoetry-git-{}'.format(dependency.name))) try: git = Git() git.clone(dependency.source, tmp_dir) git.checkout(dependency.reference, tmp_dir) revision = git.rev_parse(dependency.reference, tmp_dir).strip() if dependency.tag or dependency.rev: revision = dependency.reference pyproject = TomlFile(tmp_dir / 'pyproject.toml') pyproject_content = None has_poetry = False if pyproject.exists(): pyproject_content = pyproject.read(True) has_poetry = ('tool' in pyproject_content and 'poetry' in pyproject_content['tool']) if pyproject_content and has_poetry: # If a pyproject.toml file exists # We use it to get the information we need info = pyproject_content['tool']['poetry'] name = info['name'] version = info['version'] package = Package(name, version, version) package.source_type = dependency.vcs package.source_url = dependency.source package.source_reference = dependency.reference for req_name, req_constraint in info['dependencies'].items(): if req_name == 'python': package.python_versions = req_constraint continue package.add_dependency(req_name, req_constraint) else: # We need to use setup.py here # to figure the information we need # We need to place ourselves in the proper # folder for it to work venv = Venv.create(self._io) current_dir = os.getcwd() os.chdir(tmp_dir.as_posix()) try: venv.run('python', 'setup.py', 'egg_info') egg_info = list(tmp_dir.glob('*.egg-info'))[0] meta = pkginfo.UnpackedSDist(str(egg_info)) if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / 'requires.txt' if requires.exists(): with requires.open() as f: reqs = parse_requires(f.read()) package = Package(meta.name, meta.version) for req in reqs: package.requires.append(dependency_from_pep_508(req)) except Exception: raise finally: os.chdir(current_dir) package.source_type = 'git' package.source_url = dependency.source package.source_reference = revision except Exception: raise finally: shutil.rmtree(tmp_dir.as_posix()) return [package]
def solve(self, use_latest=None): # type: (...) -> List[Operation] with self._provider.progress(): start = time.time() packages, depths = self._solve(use_latest=use_latest) end = time.time() if len(self._branches) > 1: self._provider.debug( "Complete version solving took {:.3f} seconds for {} branches" .format(end - start, len(self._branches[1:]))) self._provider.debug("Resolved for branches: {}".format( ", ".join("({})".format(b) for b in self._branches[1:]))) operations = [] for package in packages: installed = False for pkg in self._installed.packages: if package.name == pkg.name: installed = True if pkg.source_type == "git" and package.source_type == "git": # Trying to find the currently installed version for locked in self._locked.packages: if (locked.name == pkg.name and locked.source_type == pkg.source_type and locked.source_url == pkg.source_url and locked.source_reference == pkg.source_reference): pkg = Package(pkg.name, locked.version) pkg.source_type = "git" pkg.source_url = locked.source_url pkg.source_reference = locked.source_reference break if pkg.source_url != package.source_url or ( pkg.source_reference != package.source_reference and not pkg.source_reference.startswith( package.source_reference)): operations.append(Update(pkg, package)) else: operations.append( Install(package).skip("Already installed")) elif package.version != pkg.version: # Checking version operations.append(Update(pkg, package)) else: operations.append( Install(package).skip("Already installed")) break if not installed: operations.append(Install(package)) # Checking for removals for pkg in self._locked.packages: remove = True for package in packages: if pkg.name == package.name: remove = False break if remove: skip = True for installed in self._installed.packages: if installed.name == pkg.name: skip = False break op = Uninstall(pkg) if skip: op.skip("Not currently installed") operations.append(op) return sorted( operations, key=lambda o: ( o.job_type == "uninstall", # Packages to be uninstalled have no depth so we default to 0 # since it actually doesn't matter since removals are always on top. -depths[packages.index(o.package)] if o.job_type != "uninstall" else 0, o.package.name, o.package.version, ), )
def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package] """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency.vcs != "git": raise ValueError("Unsupported VCS dependency {}".format(dependency.vcs)) tmp_dir = Path(mkdtemp(prefix="pypoetry-git-{}".format(dependency.name))) try: git = Git() git.clone(dependency.source, tmp_dir) git.checkout(dependency.reference, tmp_dir) revision = git.rev_parse(dependency.reference, tmp_dir).strip() if dependency.tag or dependency.rev: revision = dependency.reference pyproject = TomlFile(tmp_dir / "pyproject.toml") pyproject_content = None has_poetry = False if pyproject.exists(): pyproject_content = pyproject.read() has_poetry = ( "tool" in pyproject_content and "poetry" in pyproject_content["tool"] ) if pyproject_content and has_poetry: # If a pyproject.toml file exists # We use it to get the information we need info = pyproject_content["tool"]["poetry"] name = info["name"] version = info["version"] package = Package(name, version, version) package.source_type = dependency.vcs package.source_url = dependency.source package.source_reference = dependency.reference for req_name, req_constraint in info["dependencies"].items(): if req_name == "python": package.python_versions = req_constraint continue package.add_dependency(req_name, req_constraint) else: # We need to use setup.py here # to figure the information we need # We need to place ourselves in the proper # folder for it to work venv = Venv.create(self._io) current_dir = os.getcwd() os.chdir(tmp_dir.as_posix()) try: venv.run("python", "setup.py", "egg_info") # Sometimes pathlib will fail on recursive # symbolic links, so we need to workaround it # and use the glob module instead. # Note that this does not happen with pathlib2 # so it's safe to use it for Python < 3.4. if PY35: egg_info = next( Path(p) for p in glob.glob( os.path.join(str(tmp_dir), "**", "*.egg-info"), recursive=True, ) ) else: egg_info = next(tmp_dir.glob("**/*.egg-info")) meta = pkginfo.UnpackedSDist(str(egg_info)) if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / "requires.txt" if requires.exists(): with requires.open() as f: reqs = parse_requires(f.read()) package = Package(meta.name, meta.version) for req in reqs: dep = dependency_from_pep_508(req) if dep.in_extras: for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) package.requires.append(dep) except Exception: raise finally: os.chdir(current_dir) package.source_type = "git" package.source_url = dependency.source package.source_reference = revision except Exception: raise finally: shutil.rmtree(tmp_dir.as_posix()) if dependency.name != package.name: # For now, the dependency's name must match the actual package's name raise RuntimeError( "The dependency name for {} does not match the actual package's name: {}".format( dependency.name, package.name ) ) if dependency.extras: for extra in dependency.extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() return [package]
def search_for_vcs(self, dependency: VCSDependency) -> List[Package]: """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency.vcs != 'git': raise ValueError(f'Unsupported VCS dependency {dependency.vcs}') tmp_dir = Path(mkdtemp(prefix=f'pypoetry-git-{dependency.name}')) try: git = Git() git.clone(dependency.source, tmp_dir) git.checkout(dependency.reference, tmp_dir) revision = git.rev_parse(dependency.reference, tmp_dir).strip() if dependency.tag or dependency.rev: revision = dependency.reference poetry = TomlFile(tmp_dir / 'pyproject.toml') if poetry.exists(): # If a pyproject.toml file exists # We use it to get the information we need info = poetry.read() name = info['package']['name'] version = info['package']['version'] package = Package(name, version, version) for req_name, req_constraint in info['dependencies'].items(): package.add_dependency(req_name, req_constraint) else: # We need to use setup.py here # to figure the information we need # We need to place ourselves in the proper # folder for it to work current_dir = os.getcwd() os.chdir(tmp_dir.as_posix()) try: venv = Venv.create() output = venv.run('python', 'setup.py', '--name', '--version') output = output.split('\n') name = output[-3] version = output[-2] package = Package(name, version, version) # Figure out a way to get requirements except Exception: raise finally: os.chdir(current_dir) package.source_type = 'git' package.source_url = dependency.source package.source_reference = revision except Exception: raise finally: shutil.rmtree(tmp_dir.as_posix()) return [package]