Skip to content

Commit

Permalink
refactor: split off functions to get direct origin dependencies from …
Browse files Browse the repository at this point in the history
…provider (#7693)
  • Loading branch information
radoering committed May 5, 2023
1 parent 1b611f5 commit 5edb992
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 108 deletions.
110 changes: 110 additions & 0 deletions src/poetry/packages/direct_origin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from __future__ import annotations

import functools
import os
import tempfile
import urllib.parse

from pathlib import Path
from typing import TYPE_CHECKING

from poetry.inspection.info import PackageInfo
from poetry.inspection.info import PackageInfoError
from poetry.utils.helpers import download_file
from poetry.utils.helpers import get_file_hash
from poetry.vcs.git import Git


if TYPE_CHECKING:
from poetry.core.packages.package import Package


@functools.lru_cache(maxsize=None)
def _get_package_from_git(
url: str,
branch: str | None = None,
tag: str | None = None,
rev: str | None = None,
subdirectory: str | None = None,
source_root: Path | None = None,
) -> Package:
source = Git.clone(
url=url,
source_root=source_root,
branch=branch,
tag=tag,
revision=rev,
clean=False,
)
revision = Git.get_revision(source)

path = Path(source.path)
if subdirectory:
path = path.joinpath(subdirectory)

package = DirectOrigin.get_package_from_directory(path)
package._source_type = "git"
package._source_url = url
package._source_reference = rev or tag or branch or "HEAD"
package._source_resolved_reference = revision
package._source_subdirectory = subdirectory

return package


class DirectOrigin:
@classmethod
def get_package_from_file(cls, file_path: Path) -> Package:
try:
package = PackageInfo.from_path(path=file_path).to_package(
root_dir=file_path
)
except PackageInfoError:
raise RuntimeError(
f"Unable to determine package info from path: {file_path}"
)

return package

@classmethod
def get_package_from_directory(cls, directory: Path) -> Package:
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)

@classmethod
def get_package_from_url(cls, url: str) -> Package:
file_name = os.path.basename(urllib.parse.urlparse(url).path)
with tempfile.TemporaryDirectory() as temp_dir:
dest = Path(temp_dir) / file_name
download_file(url, dest)
package = cls.get_package_from_file(dest)

package.files = [
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
]

package._source_type = "url"
package._source_url = url

return package

@staticmethod
def get_package_from_vcs(
vcs: str,
url: str,
branch: str | None = None,
tag: str | None = None,
rev: str | None = None,
subdirectory: str | None = None,
source_root: Path | None = None,
) -> Package:
if vcs != "git":
raise ValueError(f"Unsupported VCS dependency {vcs}")

return _get_package_from_git(
url=url,
branch=branch,
tag=tag,
rev=rev,
subdirectory=subdirectory,
source_root=source_root,
)
108 changes: 6 additions & 102 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
from __future__ import annotations

import functools
import logging
import os
import re
import tempfile
import time
import urllib.parse

from collections import defaultdict
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING
from typing import cast

Expand All @@ -22,26 +17,24 @@
from poetry.core.version.markers import EmptyMarker
from poetry.core.version.markers import MarkerUnion

from poetry.inspection.info import PackageInfo
from poetry.inspection.info import PackageInfoError
from poetry.mixology.incompatibility import Incompatibility
from poetry.mixology.incompatibility_cause import DependencyCause
from poetry.mixology.incompatibility_cause import PythonCause
from poetry.mixology.term import Term
from poetry.packages import DependencyPackage
from poetry.packages.direct_origin import DirectOrigin
from poetry.packages.package_collection import PackageCollection
from poetry.puzzle.exceptions import OverrideNeeded
from poetry.repositories.exceptions import PackageNotFound
from poetry.utils.helpers import download_file
from poetry.utils.helpers import get_file_hash
from poetry.vcs.git import Git


if TYPE_CHECKING:
from collections.abc import Callable
from collections.abc import Collection
from collections.abc import Iterable
from collections.abc import Iterator
from pathlib import Path

from cleo.io.io import IO
from packaging.utils import NormalizedName
Expand Down Expand Up @@ -100,39 +93,6 @@ def _formatter_elapsed(self) -> str:
return f"{elapsed:.1f}s"


@functools.lru_cache(maxsize=None)
def _get_package_from_git(
url: str,
branch: str | None = None,
tag: str | None = None,
rev: str | None = None,
subdirectory: str | None = None,
source_root: Path | None = None,
) -> Package:
source = Git.clone(
url=url,
source_root=source_root,
branch=branch,
tag=tag,
revision=rev,
clean=False,
)
revision = Git.get_revision(source)

path = Path(source.path)
if subdirectory:
path = path.joinpath(subdirectory)

package = Provider.get_package_from_directory(path)
package._source_type = "git"
package._source_url = url
package._source_reference = rev or tag or branch or "HEAD"
package._source_resolved_reference = revision
package._source_subdirectory = subdirectory

return package


class Provider:
UNSAFE_PACKAGES: set[str] = set()

Expand Down Expand Up @@ -351,7 +311,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
Basically, we clone the repository in a temporary directory
and get the information we need by checking out the specified reference.
"""
package = self.get_package_from_vcs(
package = DirectOrigin.get_package_from_vcs(
dependency.vcs,
dependency.source,
branch=dependency.branch,
Expand All @@ -368,31 +328,9 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:

return package

@staticmethod
def get_package_from_vcs(
vcs: str,
url: str,
branch: str | None = None,
tag: str | None = None,
rev: str | None = None,
subdirectory: str | None = None,
source_root: Path | None = None,
) -> Package:
if vcs != "git":
raise ValueError(f"Unsupported VCS dependency {vcs}")

return _get_package_from_git(
url=url,
branch=branch,
tag=tag,
rev=rev,
subdirectory=subdirectory,
source_root=source_root,
)

def _search_for_file(self, dependency: FileDependency) -> Package:
dependency.validate(raise_error=True)
package = self.get_package_from_file(dependency.full_path)
package = DirectOrigin.get_package_from_file(dependency.full_path)

self.validate_package_for_dependency(dependency=dependency, package=package)

Expand All @@ -408,22 +346,9 @@ def _search_for_file(self, dependency: FileDependency) -> Package:

return package

@classmethod
def get_package_from_file(cls, file_path: Path) -> Package:
try:
package = PackageInfo.from_path(path=file_path).to_package(
root_dir=file_path
)
except PackageInfoError:
raise RuntimeError(
f"Unable to determine package info from path: {file_path}"
)

return package

def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
dependency.validate(raise_error=True)
package = self.get_package_from_directory(dependency.full_path)
package = DirectOrigin.get_package_from_directory(dependency.full_path)

self.validate_package_for_dependency(dependency=dependency, package=package)

Expand All @@ -434,12 +359,8 @@ def _search_for_directory(self, dependency: DirectoryDependency) -> Package:

return package

@classmethod
def get_package_from_directory(cls, directory: Path) -> Package:
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)

def _search_for_url(self, dependency: URLDependency) -> Package:
package = self.get_package_from_url(dependency.url)
package = DirectOrigin.get_package_from_url(dependency.url)

self.validate_package_for_dependency(dependency=dependency, package=package)

Expand All @@ -453,23 +374,6 @@ def _search_for_url(self, dependency: URLDependency) -> Package:

return package

@classmethod
def get_package_from_url(cls, url: str) -> Package:
file_name = os.path.basename(urllib.parse.urlparse(url).path)
with tempfile.TemporaryDirectory() as temp_dir:
dest = Path(temp_dir) / file_name
download_file(url, dest)
package = cls.get_package_from_file(dest)

package.files = [
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
]

package._source_type = "url"
package._source_url = url

return package

def _get_dependencies_with_overrides(
self, dependencies: list[Dependency], package: DependencyPackage
) -> list[Dependency]:
Expand Down
10 changes: 5 additions & 5 deletions src/poetry/utils/dependency_specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from poetry.core.packages.dependency import Dependency
from tomlkit.items import InlineTable

from poetry.puzzle.provider import Provider
from poetry.packages.direct_origin import DirectOrigin


if TYPE_CHECKING:
Expand Down Expand Up @@ -120,7 +120,7 @@ def _parse_git_url(self, requirement: str) -> DependencySpec | None:
pair["subdirectory"] = parsed.subdirectory

source_root = self._env.path.joinpath("src") if self._env else None
package = Provider.get_package_from_vcs(
package = DirectOrigin.get_package_from_vcs(
"git",
url=url.url,
rev=pair.get("rev"),
Expand All @@ -139,7 +139,7 @@ def _parse_url(self, requirement: str) -> DependencySpec | None:
return self._parse_git_url(requirement)

if url_parsed.scheme in ["http", "https"]:
package = Provider.get_package_from_url(requirement)
package = DirectOrigin.get_package_from_url(requirement)
assert package.source_url is not None
return {"name": package.name, "url": package.source_url}

Expand All @@ -158,9 +158,9 @@ def _parse_path(self, requirement: str) -> DependencySpec | None:
path = self._cwd.joinpath(requirement)

if path.is_file():
package = Provider.get_package_from_file(path.resolve())
package = DirectOrigin.get_package_from_file(path.resolve())
else:
package = Provider.get_package_from_directory(path.resolve())
package = DirectOrigin.get_package_from_directory(path.resolve())

return {
"name": package.name,
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def mock_user_config_dir(mocker: MockerFixture, config_dir: Path) -> None:
def download_mock(mocker: MockerFixture) -> None:
# Patch download to not download anything but to just copy from fixtures
mocker.patch("poetry.utils.helpers.download_file", new=mock_download)
mocker.patch("poetry.puzzle.provider.download_file", new=mock_download)
mocker.patch("poetry.packages.direct_origin.download_file", new=mock_download)
mocker.patch("poetry.repositories.http_repository.download_file", new=mock_download)


Expand Down

0 comments on commit 5edb992

Please sign in to comment.