Skip to content

Commit

Permalink
More complicated conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
uranusjr committed Jul 30, 2021
1 parent dd8a117 commit 3bf6c7c
Showing 1 changed file with 40 additions and 3 deletions.
43 changes: 40 additions & 3 deletions src/pip/_internal/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import pathlib
from optparse import Values
from typing import Iterator, List, NamedTuple, Optional
from typing import Iterator, List, NamedTuple, Optional, Tuple

from pip._vendor.packaging.utils import canonicalize_name

Expand Down Expand Up @@ -66,6 +66,33 @@ class _PackageInfo(NamedTuple):
files: Optional[List[str]]


def _covert_legacy_entry(entry: Tuple[str, ...], info: Tuple[str, ...]) -> str:
"""Convert a legacy installed-files.txt path into modern RECORD path.
The legacy format stores paths relative to the info directory, while the
modern format stores paths relative to the package root, e.g. the
site-packages directory.
:param entry: Path parts of the installed-files.txt entry.
:param info: Path parts of the egg-info directory relative to package root.
:returns: The converted entry.
For best compatibility with symlinks, this does not use ``abspath()`` or
``Path.resolve()``, but tries to work with path parts:
1. While ``entry`` starts with ``..``, remove the equal amounts of parts
from ``info``; if ``info`` is empty, start appending ``..`` instead.
2. Join the two directly.
"""
while entry and entry[0] == "..":
if not info or info[-1] == "..":
info += ("..",)
else:
info = info[:-1]
entry = entry[1:]
return str(pathlib.Path(*info, *entry))


def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
"""
Gather details from installed distributions. Print distribution name,
Expand Down Expand Up @@ -100,7 +127,8 @@ def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]:
text = dist.read_text('RECORD')
except FileNotFoundError:
return None
return (row[0] for row in csv.reader(text.splitlines()))
# This extra Path-str cast normalizes entries.
return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines()))

def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[str]]:
try:
Expand All @@ -112,7 +140,16 @@ def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[str]]:
info = dist.info_directory
if root is None or info is None:
return paths
return (str(pathlib.Path(info, p).relative_to(root)) for p in paths)
try:
info_rel = pathlib.Path(info).relative_to(root)
except ValueError: # info is not relative to root.
return paths
if not info_rel.parts: # info *is* root.
return paths
return (
_covert_legacy_entry(pathlib.Path(p).parts, info_rel.parts)
for p in paths
)

for query_name in query_names:
try:
Expand Down

0 comments on commit 3bf6c7c

Please sign in to comment.