pex 2.65.0__py2.py3-none-any.whl → 2.66.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pex might be problematic. Click here for more details.
- pex/docs/html/_pagefind/fragment/en_30a274f.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_32bca6c.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_415e2ea.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_bcccea1.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_ca898f2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_d4c744d.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_f2ec11e.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_f3e451d.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/{en_71e2485.pf_index → en_5564892.pf_index} +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_421bc6c608.pf_meta +0 -0
- pex/docs/html/_static/documentation_options.js +1 -1
- pex/docs/html/api/vars.html +5 -5
- pex/docs/html/buildingpex.html +5 -5
- pex/docs/html/genindex.html +5 -5
- pex/docs/html/index.html +5 -5
- pex/docs/html/recipes.html +5 -5
- pex/docs/html/scie.html +5 -5
- pex/docs/html/search.html +5 -5
- pex/docs/html/whatispex.html +5 -5
- pex/hashing.py +71 -9
- pex/pex_builder.py +1 -4
- pex/pip/tool.py +3 -3
- pex/pip/vcs.py +93 -44
- pex/pip/version.py +7 -0
- pex/resolve/lock_downloader.py +1 -0
- pex/resolve/locker.py +30 -14
- pex/resolve/lockfile/create.py +1 -6
- pex/resolve/pre_resolved_resolver.py +1 -7
- pex/resolver.py +40 -35
- pex/version.py +1 -1
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/METADATA +4 -4
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/RECORD +38 -38
- pex/docs/html/_pagefind/fragment/en_111cec6.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_57535ac.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_68579f8.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_b915203.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_d450b85.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_eb89be5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_ff882aa.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_ffc2e0e.pf_fragment +0 -0
- pex/docs/html/_pagefind/pagefind.en_f11d4148c9.pf_meta +0 -0
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/WHEEL +0 -0
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/entry_points.txt +0 -0
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/licenses/LICENSE +0 -0
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/pylock/pylock.toml +0 -0
- {pex-2.65.0.dist-info → pex-2.66.1.dist-info}/top_level.txt +0 -0
pex/pip/vcs.py
CHANGED
|
@@ -3,26 +3,42 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
|
-
import glob
|
|
7
6
|
import os
|
|
8
7
|
import re
|
|
9
8
|
|
|
10
9
|
from pex import hashing
|
|
11
10
|
from pex.artifact_url import VCS, Fingerprint
|
|
12
|
-
from pex.common import is_pyc_dir, is_pyc_file
|
|
11
|
+
from pex.common import is_pyc_dir, is_pyc_file
|
|
12
|
+
from pex.exceptions import reportable_unexpected_error_msg
|
|
13
13
|
from pex.hashing import Sha256
|
|
14
14
|
from pex.pep_440 import Version
|
|
15
15
|
from pex.pep_503 import ProjectName
|
|
16
16
|
from pex.result import Error, try_
|
|
17
|
-
from pex.tracer import TRACER
|
|
18
17
|
from pex.typing import TYPE_CHECKING
|
|
19
18
|
|
|
20
19
|
if TYPE_CHECKING:
|
|
21
|
-
|
|
20
|
+
# N.B.: The `re.Pattern` type is not available in all Python versions Pex supports.
|
|
21
|
+
from re import Pattern # type: ignore[attr-defined]
|
|
22
|
+
from typing import Callable, Optional, Text, Tuple, Union
|
|
22
23
|
|
|
23
24
|
from pex.hashing import HintedDigest
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def _project_name_re(project_name):
|
|
28
|
+
# type: (ProjectName) -> str
|
|
29
|
+
return project_name.normalized.replace("-", "[-_.]+")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _built_source_dist_pattern(project_name):
|
|
33
|
+
# type: (ProjectName) -> Pattern
|
|
34
|
+
return re.compile(
|
|
35
|
+
r"(?P<project_name>{project_name_re})-(?P<version>.+)\.zip".format(
|
|
36
|
+
project_name_re=_project_name_re(project_name)
|
|
37
|
+
),
|
|
38
|
+
re.IGNORECASE,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
26
42
|
def _find_built_source_dist(
|
|
27
43
|
build_dir, # type: str
|
|
28
44
|
project_name, # type: ProjectName
|
|
@@ -34,12 +50,7 @@ def _find_built_source_dist(
|
|
|
34
50
|
# encoded in: `pip._internal.req.req_install.InstallRequirement.archive`.
|
|
35
51
|
|
|
36
52
|
listing = os.listdir(build_dir)
|
|
37
|
-
pattern =
|
|
38
|
-
r"{project_name}-(?P<version>.+)\.zip".format(
|
|
39
|
-
project_name=project_name.normalized.replace("-", "[-_.]+")
|
|
40
|
-
),
|
|
41
|
-
re.IGNORECASE,
|
|
42
|
-
)
|
|
53
|
+
pattern = _built_source_dist_pattern(project_name)
|
|
43
54
|
for name in listing:
|
|
44
55
|
match = pattern.match(name)
|
|
45
56
|
if match and Version(match.group("version")) == version:
|
|
@@ -58,23 +69,66 @@ def _find_built_source_dist(
|
|
|
58
69
|
|
|
59
70
|
def fingerprint_downloaded_vcs_archive(
|
|
60
71
|
download_dir, # type: str
|
|
61
|
-
project_name, # type:
|
|
62
|
-
version, # type:
|
|
72
|
+
project_name, # type: ProjectName
|
|
73
|
+
version, # type: Version
|
|
63
74
|
vcs, # type: VCS.Value
|
|
64
75
|
):
|
|
65
76
|
# type: (...) -> Tuple[Fingerprint, str]
|
|
66
77
|
|
|
67
78
|
archive_path = try_(
|
|
68
|
-
_find_built_source_dist(
|
|
69
|
-
build_dir=download_dir, project_name=ProjectName(project_name), version=Version(version)
|
|
70
|
-
)
|
|
79
|
+
_find_built_source_dist(build_dir=download_dir, project_name=project_name, version=version)
|
|
71
80
|
)
|
|
72
81
|
digest = Sha256()
|
|
73
|
-
digest_vcs_archive(archive_path=archive_path, vcs=vcs, digest=digest)
|
|
82
|
+
digest_vcs_archive(project_name=project_name, archive_path=archive_path, vcs=vcs, digest=digest)
|
|
74
83
|
return Fingerprint.from_digest(digest), archive_path
|
|
75
84
|
|
|
76
85
|
|
|
86
|
+
def _vcs_dir_filter(
|
|
87
|
+
vcs, # type: VCS.Value
|
|
88
|
+
project_name, # type: ProjectName
|
|
89
|
+
):
|
|
90
|
+
# type: (...) -> Callable[[Text], bool]
|
|
91
|
+
|
|
92
|
+
# Ignore VCS control directories for the purposes of fingerprinting the version controlled
|
|
93
|
+
# source tree. VCS control directories can contain non-reproducible content (Git at least
|
|
94
|
+
# has files that contain timestamps).
|
|
95
|
+
#
|
|
96
|
+
# We cannot prune these directories from the source archive directly unfortunately since
|
|
97
|
+
# some build processes use VCS version information to derive their version numbers (C.F.:
|
|
98
|
+
# https://pypi.org/project/setuptools-scm/). As such, we'll get a stable fingerprint, but be
|
|
99
|
+
# forced to re-build a wheel each time the VCS requirement is re-locked later, even when it
|
|
100
|
+
# hashes the same.
|
|
101
|
+
vcs_control_dir = ".{vcs}".format(vcs=vcs)
|
|
102
|
+
|
|
103
|
+
# N.B.: If the VCS project uses setuptools as its build backend, depending on the version of
|
|
104
|
+
# Pip used, the VCS checkout can have a `<project name>.egg-info/` directory littering its root
|
|
105
|
+
# left over from Pip generating project metadata to determine version and dependencies. No other
|
|
106
|
+
# well known build-backend has this problem at this time (checked hatchling, poetry-core,
|
|
107
|
+
# pdm-backend and uv_build).
|
|
108
|
+
# C.F.: https://github.com/pypa/pip/pull/13602
|
|
109
|
+
egg_info_dir_re = re.compile(
|
|
110
|
+
r"^{project_name_re}\.egg-info$".format(project_name_re=_project_name_re(project_name)),
|
|
111
|
+
re.IGNORECASE,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def vcs_dir_filter(dir_path):
|
|
115
|
+
# type: (Text) -> bool
|
|
116
|
+
if is_pyc_dir(dir_path):
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
base_dir_name = dir_path.split(os.sep)[0]
|
|
120
|
+
return base_dir_name != vcs_control_dir and not egg_info_dir_re.match(base_dir_name)
|
|
121
|
+
|
|
122
|
+
return vcs_dir_filter
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _vcs_file_filter(vcs):
|
|
126
|
+
# type: (VCS.Value) -> Callable[[Text], bool]
|
|
127
|
+
return lambda f: not is_pyc_file(f)
|
|
128
|
+
|
|
129
|
+
|
|
77
130
|
def digest_vcs_archive(
|
|
131
|
+
project_name, # type: ProjectName
|
|
78
132
|
archive_path, # type: str
|
|
79
133
|
vcs, # type: VCS.Value
|
|
80
134
|
digest, # type: HintedDigest
|
|
@@ -84,22 +138,32 @@ def digest_vcs_archive(
|
|
|
84
138
|
# All VCS requirements are prepared as zip archives as encoded in:
|
|
85
139
|
# `pip._internal.req.req_install.InstallRequirement.archive` and the archive is already offset
|
|
86
140
|
# by a subdirectory (if any).
|
|
87
|
-
with TRACER.timed(
|
|
88
|
-
"Digesting {archive} {vcs} archive".format(archive=os.path.basename(archive_path), vcs=vcs)
|
|
89
|
-
), temporary_dir() as chroot, open_zip(archive_path) as archive:
|
|
90
|
-
# TODO(John Sirois): Consider implementing zip_hash to avoid the extractall.
|
|
91
|
-
archive.extractall(chroot)
|
|
92
141
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
142
|
+
# The zip archives created by Pip have a single project name top-level directory housing
|
|
143
|
+
# the full clone. We look for that to get a consistent clone hash with a bare clone.
|
|
144
|
+
match = _built_source_dist_pattern(project_name).match(os.path.basename(archive_path))
|
|
145
|
+
if match is None:
|
|
146
|
+
raise AssertionError(
|
|
147
|
+
reportable_unexpected_error_msg(
|
|
148
|
+
"Failed to determine the project name prefix for the VCS zip {zip} with expected "
|
|
149
|
+
"canonical project name {project_name}".format(
|
|
150
|
+
zip=archive_path, project_name=project_name
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
top_dir = match.group("project_name")
|
|
98
155
|
|
|
99
|
-
|
|
156
|
+
hashing.zip_hash(
|
|
157
|
+
zip_path=archive_path,
|
|
158
|
+
digest=digest,
|
|
159
|
+
relpath=top_dir,
|
|
160
|
+
dir_filter=_vcs_dir_filter(vcs, project_name),
|
|
161
|
+
file_filter=_vcs_file_filter(vcs),
|
|
162
|
+
)
|
|
100
163
|
|
|
101
164
|
|
|
102
165
|
def digest_vcs_repo(
|
|
166
|
+
project_name, # type: ProjectName
|
|
103
167
|
repo_path, # type: str
|
|
104
168
|
vcs, # type: VCS.Value
|
|
105
169
|
digest, # type: HintedDigest
|
|
@@ -107,24 +171,9 @@ def digest_vcs_repo(
|
|
|
107
171
|
):
|
|
108
172
|
# type: (...) -> None
|
|
109
173
|
|
|
110
|
-
# Ignore VCS control directories for the purposes of fingerprinting the version controlled
|
|
111
|
-
# source tree. VCS control directories can contain non-reproducible content (Git at least
|
|
112
|
-
# has files that contain timestamps).
|
|
113
|
-
#
|
|
114
|
-
# We cannot prune these directories from the source archive directly unfortunately since
|
|
115
|
-
# some build processes use VCS version information to derive their version numbers (C.F.:
|
|
116
|
-
# https://pypi.org/project/setuptools-scm/). As such, we'll get a stable fingerprint, but be
|
|
117
|
-
# forced to re-build a wheel each time the VCS requirement is re-locked later, even when it
|
|
118
|
-
# hashes the same.
|
|
119
|
-
vcs_control_dir = ".{vcs}".format(vcs=vcs)
|
|
120
|
-
|
|
121
174
|
hashing.dir_hash(
|
|
122
175
|
directory=os.path.join(repo_path, subdirectory) if subdirectory else repo_path,
|
|
123
176
|
digest=digest,
|
|
124
|
-
dir_filter=(
|
|
125
|
-
|
|
126
|
-
not is_pyc_dir(dir_path) and os.path.basename(dir_path) != vcs_control_dir
|
|
127
|
-
)
|
|
128
|
-
),
|
|
129
|
-
file_filter=lambda f: not is_pyc_file(f),
|
|
177
|
+
dir_filter=_vcs_dir_filter(vcs, project_name),
|
|
178
|
+
file_filter=_vcs_file_filter(vcs),
|
|
130
179
|
)
|
pex/pip/version.py
CHANGED
|
@@ -369,6 +369,13 @@ class PipVersion(Enum["PipVersionValue"]):
|
|
|
369
369
|
requires_python=">=3.9,<3.16",
|
|
370
370
|
)
|
|
371
371
|
|
|
372
|
+
v25_3 = PipVersionValue(
|
|
373
|
+
version="25.3",
|
|
374
|
+
setuptools_version="80.9.0",
|
|
375
|
+
wheel_version="0.45.1",
|
|
376
|
+
requires_python=">=3.9,<3.16",
|
|
377
|
+
)
|
|
378
|
+
|
|
372
379
|
VENDORED = v20_3_4_patched
|
|
373
380
|
LATEST = LatestPipVersion()
|
|
374
381
|
LATEST_COMPATIBLE = LatestCompatiblePipVersion()
|
pex/resolve/lock_downloader.py
CHANGED
|
@@ -154,6 +154,7 @@ class VCSArtifactDownloadManager(DownloadManager[VCSArtifact]):
|
|
|
154
154
|
local_distribution = downloaded_vcs.local_distributions[0]
|
|
155
155
|
filename = os.path.basename(local_distribution.path)
|
|
156
156
|
digest_vcs_archive(
|
|
157
|
+
project_name=project_name,
|
|
157
158
|
archive_path=local_distribution.path,
|
|
158
159
|
vcs=artifact.vcs,
|
|
159
160
|
digest=digest,
|
pex/resolve/locker.py
CHANGED
|
@@ -30,6 +30,7 @@ from pex.resolve.pep_691.model import Endpoint
|
|
|
30
30
|
from pex.resolve.resolved_requirement import PartialArtifact, Pin, ResolvedRequirement
|
|
31
31
|
from pex.resolve.resolvers import Resolver
|
|
32
32
|
from pex.resolve.target_system import UniversalTarget
|
|
33
|
+
from pex.result import try_
|
|
33
34
|
from pex.targets import Target
|
|
34
35
|
from pex.typing import TYPE_CHECKING
|
|
35
36
|
|
|
@@ -291,6 +292,16 @@ class Locker(LogAnalyzer):
|
|
|
291
292
|
def _maybe_record_wheel(self, url):
|
|
292
293
|
# type: (str) -> ArtifactURL
|
|
293
294
|
artifact_url = self.parse_url_and_maybe_record_fingerprint(url)
|
|
295
|
+
|
|
296
|
+
# N.B.: Lock resolves driven by `pip install --dry-run --report` will only consult PEP-658
|
|
297
|
+
# `.whl.metadata` side-car files in the happy path; so we must use these as a proxy for the
|
|
298
|
+
# `.whl` file they are paired with.
|
|
299
|
+
# See: https://peps.python.org/pep-0658/
|
|
300
|
+
if not self._lock_is_via_pip_download and artifact_url.url_info.path.endswith(".metadata"):
|
|
301
|
+
artifact_url = ArtifactURL.from_url_info(
|
|
302
|
+
artifact_url.url_info._replace(path=artifact_url.url_info.path[:-9])
|
|
303
|
+
)
|
|
304
|
+
|
|
294
305
|
if artifact_url.is_wheel:
|
|
295
306
|
pin, partial_artifact = self._extract_resolve_data(artifact_url)
|
|
296
307
|
|
|
@@ -371,8 +382,8 @@ class Locker(LogAnalyzer):
|
|
|
371
382
|
if isinstance(artifact_url.scheme, VCSScheme):
|
|
372
383
|
source_fingerprint, archive_path = fingerprint_downloaded_vcs_archive(
|
|
373
384
|
download_dir=self._download_dir,
|
|
374
|
-
project_name=
|
|
375
|
-
version=
|
|
385
|
+
project_name=build_result.pin.project_name,
|
|
386
|
+
version=build_result.pin.version,
|
|
376
387
|
vcs=artifact_url.scheme.vcs,
|
|
377
388
|
)
|
|
378
389
|
verified = True
|
|
@@ -407,12 +418,14 @@ class Locker(LogAnalyzer):
|
|
|
407
418
|
os.path.basename(artifact_url.path)
|
|
408
419
|
] = build_result.pin
|
|
409
420
|
else:
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
421
|
+
try_(
|
|
422
|
+
digest_local_project(
|
|
423
|
+
directory=artifact_url.path,
|
|
424
|
+
digest=digest,
|
|
425
|
+
pip_version=self._pip_version,
|
|
426
|
+
target=self._target,
|
|
427
|
+
resolver=self._resolver,
|
|
428
|
+
)
|
|
416
429
|
)
|
|
417
430
|
self._local_projects.add(artifact_url.path)
|
|
418
431
|
self._saved.add(build_result.pin)
|
|
@@ -445,6 +458,7 @@ class Locker(LogAnalyzer):
|
|
|
445
458
|
if isinstance(artifact_url.scheme, VCSScheme):
|
|
446
459
|
digest = Sha256()
|
|
447
460
|
digest_vcs_repo(
|
|
461
|
+
project_name=build_result.pin.project_name,
|
|
448
462
|
repo_path=build_result.path,
|
|
449
463
|
vcs=artifact_url.scheme.vcs,
|
|
450
464
|
digest=digest,
|
|
@@ -479,12 +493,14 @@ class Locker(LogAnalyzer):
|
|
|
479
493
|
os.path.basename(artifact_url.path)
|
|
480
494
|
] = build_result.pin
|
|
481
495
|
else:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
496
|
+
try_(
|
|
497
|
+
digest_local_project(
|
|
498
|
+
directory=artifact_url.path,
|
|
499
|
+
digest=digest,
|
|
500
|
+
pip_version=self._pip_version,
|
|
501
|
+
target=self._target,
|
|
502
|
+
resolver=self._resolver,
|
|
503
|
+
)
|
|
488
504
|
)
|
|
489
505
|
self._local_projects.add(artifact_url.path)
|
|
490
506
|
self._saved.add(build_result.pin)
|
pex/resolve/lockfile/create.py
CHANGED
|
@@ -357,8 +357,6 @@ class LockObserver(ResolveObserver):
|
|
|
357
357
|
target=local_distribution.download_target,
|
|
358
358
|
source_path=local_distribution.path,
|
|
359
359
|
subdirectory=local_distribution.subdirectory,
|
|
360
|
-
resolver=self.resolver,
|
|
361
|
-
pip_version=self.package_index_configuration.pip_version,
|
|
362
360
|
)
|
|
363
361
|
)
|
|
364
362
|
|
|
@@ -369,10 +367,7 @@ class LockObserver(ResolveObserver):
|
|
|
369
367
|
lock_result = analysis.analyzer.lock_result
|
|
370
368
|
build_requests.update(
|
|
371
369
|
BuildRequest.for_directory(
|
|
372
|
-
target=analysis.download_target,
|
|
373
|
-
source_path=local_project,
|
|
374
|
-
resolver=self.resolver,
|
|
375
|
-
pip_version=self.package_index_configuration.pip_version,
|
|
370
|
+
target=analysis.download_target, source_path=local_project
|
|
376
371
|
)
|
|
377
372
|
for local_project in lock_result.local_projects
|
|
378
373
|
)
|
|
@@ -101,19 +101,13 @@ def resolve_from_dists(
|
|
|
101
101
|
extra_pip_requirements=pip_configuration.extra_requirements,
|
|
102
102
|
keyring_provider=pip_configuration.keyring_provider,
|
|
103
103
|
)
|
|
104
|
-
resolver = ConfiguredResolver(pip_configuration=pip_configuration)
|
|
105
104
|
build_requests = [
|
|
106
105
|
BuildRequest.for_file(target=target, source_path=sdist)
|
|
107
106
|
for sdist in sdists
|
|
108
107
|
for target in unique_targets
|
|
109
108
|
]
|
|
110
109
|
build_requests.extend(
|
|
111
|
-
BuildRequest.for_directory(
|
|
112
|
-
target=target,
|
|
113
|
-
source_path=local_project.path,
|
|
114
|
-
resolver=resolver,
|
|
115
|
-
pip_version=pip_configuration.version,
|
|
116
|
-
)
|
|
110
|
+
BuildRequest.for_directory(target=target, source_path=local_project.path)
|
|
117
111
|
for local_project in local_projects
|
|
118
112
|
for target in unique_targets
|
|
119
113
|
)
|
pex/resolver.py
CHANGED
|
@@ -65,6 +65,7 @@ from pex.resolve.resolvers import (
|
|
|
65
65
|
check_resolve,
|
|
66
66
|
)
|
|
67
67
|
from pex.resolve.target_system import TargetSystem, UniversalTarget
|
|
68
|
+
from pex.result import Error
|
|
68
69
|
from pex.targets import AbbreviatedPlatform, CompletePlatform, LocalInterpreter, Target, Targets
|
|
69
70
|
from pex.third_party.packaging.specifiers import SpecifierSet
|
|
70
71
|
from pex.third_party.packaging.tags import Tag
|
|
@@ -309,10 +310,7 @@ class _PipSession(object):
|
|
|
309
310
|
if isinstance(requirement, LocalProjectRequirement):
|
|
310
311
|
for request in self.requests:
|
|
311
312
|
yield BuildRequest.for_directory(
|
|
312
|
-
target=request.target,
|
|
313
|
-
source_path=requirement.path,
|
|
314
|
-
resolver=self.resolver,
|
|
315
|
-
pip_version=self.pip_version,
|
|
313
|
+
target=request.target, source_path=requirement.path
|
|
316
314
|
)
|
|
317
315
|
|
|
318
316
|
def generate_reports(self, max_parallel_jobs=None):
|
|
@@ -594,12 +592,17 @@ def _fingerprint_directory(path):
|
|
|
594
592
|
return CacheHelper.dir_hash(path, digest=_hasher())
|
|
595
593
|
|
|
596
594
|
|
|
595
|
+
class BuildError(Exception):
|
|
596
|
+
pass
|
|
597
|
+
|
|
598
|
+
|
|
597
599
|
def _fingerprint_local_project(
|
|
598
600
|
path, # type: str
|
|
599
601
|
target, # type: Target
|
|
600
602
|
resolver=None, # type: Optional[Resolver]
|
|
601
603
|
pip_version=None, # type: Optional[PipVersionValue]
|
|
602
604
|
):
|
|
605
|
+
# type: (...) -> str
|
|
603
606
|
if resolver:
|
|
604
607
|
build_system_resolver = resolver
|
|
605
608
|
else:
|
|
@@ -607,17 +610,20 @@ def _fingerprint_local_project(
|
|
|
607
610
|
|
|
608
611
|
build_system_resolver = ConfiguredResolver.default()
|
|
609
612
|
|
|
610
|
-
|
|
613
|
+
hasher = _hasher()
|
|
614
|
+
result = digest_local_project(
|
|
611
615
|
directory=path,
|
|
612
|
-
digest=
|
|
616
|
+
digest=hasher,
|
|
613
617
|
target=target,
|
|
614
618
|
resolver=build_system_resolver,
|
|
615
619
|
pip_version=pip_version,
|
|
616
620
|
)
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
+
if isinstance(result, Error):
|
|
622
|
+
raise BuildError(
|
|
623
|
+
"Failed to create an sdist for hashing from the local project at {path}: "
|
|
624
|
+
"{err}".format(path=path, err=result)
|
|
625
|
+
)
|
|
626
|
+
return hasher.hexdigest()
|
|
621
627
|
|
|
622
628
|
|
|
623
629
|
def _as_download_target(target):
|
|
@@ -649,27 +655,19 @@ class BuildRequest(object):
|
|
|
649
655
|
target, # type: Union[DownloadTarget, Target]
|
|
650
656
|
source_path, # type: str
|
|
651
657
|
subdirectory=None, # type: Optional[str]
|
|
652
|
-
resolver=None, # type: Optional[Resolver]
|
|
653
|
-
pip_version=None, # type: Optional[PipVersionValue]
|
|
654
658
|
):
|
|
655
659
|
# type: (...) -> BuildRequest
|
|
656
660
|
download_target = _as_download_target(target)
|
|
657
|
-
fingerprint = _fingerprint_local_project(
|
|
658
|
-
path=source_path,
|
|
659
|
-
target=download_target.target,
|
|
660
|
-
resolver=resolver,
|
|
661
|
-
pip_version=pip_version,
|
|
662
|
-
)
|
|
663
661
|
return cls(
|
|
664
662
|
download_target=download_target,
|
|
665
663
|
source_path=source_path,
|
|
666
|
-
fingerprint=
|
|
664
|
+
fingerprint=None,
|
|
667
665
|
subdirectory=subdirectory,
|
|
668
666
|
)
|
|
669
667
|
|
|
670
668
|
download_target = attr.ib(converter=_as_download_target) # type: DownloadTarget
|
|
671
669
|
source_path = attr.ib() # type: str
|
|
672
|
-
fingerprint = attr.ib() # type: str
|
|
670
|
+
fingerprint = attr.ib() # type: Optional[str]
|
|
673
671
|
subdirectory = attr.ib() # type: Optional[str]
|
|
674
672
|
|
|
675
673
|
@property
|
|
@@ -724,12 +722,16 @@ class BuildResult(object):
|
|
|
724
722
|
source_path=None, # type: Optional[str]
|
|
725
723
|
):
|
|
726
724
|
# type: (...) -> BuildResult
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
725
|
+
if build_request.fingerprint:
|
|
726
|
+
built_wheel = BuiltWheelDir.create(
|
|
727
|
+
sdist=source_path or build_request.source_path,
|
|
728
|
+
fingerprint=build_request.fingerprint,
|
|
729
|
+
target=build_request.target,
|
|
730
|
+
)
|
|
731
|
+
target_dir = built_wheel.dist_dir
|
|
732
|
+
else:
|
|
733
|
+
target_dir = os.path.join(safe_mkdtemp(), "build")
|
|
734
|
+
return cls(request=build_request, atomic_dir=AtomicDirectory(target_dir))
|
|
733
735
|
|
|
734
736
|
request = attr.ib() # type: BuildRequest
|
|
735
737
|
_atomic_dir = attr.ib() # type: AtomicDirectory
|
|
@@ -1290,14 +1292,7 @@ class BuildAndInstallRequest(object):
|
|
|
1290
1292
|
if is_wheel(dist_path):
|
|
1291
1293
|
to_install.add(InstallRequest.create(install_request.target, dist_path))
|
|
1292
1294
|
elif os.path.isdir(dist_path):
|
|
1293
|
-
to_build.add(
|
|
1294
|
-
BuildRequest.for_directory(
|
|
1295
|
-
install_request.target,
|
|
1296
|
-
dist_path,
|
|
1297
|
-
resolver=self._resolver,
|
|
1298
|
-
pip_version=self._pip_version,
|
|
1299
|
-
)
|
|
1300
|
-
)
|
|
1295
|
+
to_build.add(BuildRequest.for_directory(install_request.target, dist_path))
|
|
1301
1296
|
else:
|
|
1302
1297
|
to_build.add(BuildRequest.for_file(install_request.target, dist_path))
|
|
1303
1298
|
already_analyzed.add(metadata.project_name)
|
|
@@ -1907,11 +1902,21 @@ def download_requests(
|
|
|
1907
1902
|
def add_build_requests(requests):
|
|
1908
1903
|
# type: (Iterable[BuildRequest]) -> None
|
|
1909
1904
|
for request in requests:
|
|
1905
|
+
if request.fingerprint:
|
|
1906
|
+
fingerprint = request.fingerprint
|
|
1907
|
+
else:
|
|
1908
|
+
production_assert(os.path.isdir(request.source_path))
|
|
1909
|
+
fingerprint = _fingerprint_local_project(
|
|
1910
|
+
path=request.source_path,
|
|
1911
|
+
target=request.target,
|
|
1912
|
+
resolver=resolver,
|
|
1913
|
+
pip_version=pip_version,
|
|
1914
|
+
)
|
|
1910
1915
|
local_distributions.append(
|
|
1911
1916
|
LocalDistribution(
|
|
1912
1917
|
download_target=request.download_target,
|
|
1913
1918
|
path=request.source_path,
|
|
1914
|
-
fingerprint=
|
|
1919
|
+
fingerprint=fingerprint,
|
|
1915
1920
|
subdirectory=request.subdirectory,
|
|
1916
1921
|
)
|
|
1917
1922
|
)
|
pex/version.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pex
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.66.1
|
|
4
4
|
Summary: The PEX packaging toolchain.
|
|
5
5
|
Home-page: https://github.com/pex-tool/pex
|
|
6
|
-
Download-URL: https://github.com/pex-tool/pex/releases/download/v2.
|
|
6
|
+
Download-URL: https://github.com/pex-tool/pex/releases/download/v2.66.1/pex
|
|
7
7
|
Author: The PEX developers
|
|
8
8
|
Author-email: developers@pex-tool.org
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
|
-
Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.
|
|
10
|
+
Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.66.1/CHANGES.md
|
|
11
11
|
Project-URL: Documentation, https://docs.pex-tool.org/
|
|
12
|
-
Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.
|
|
12
|
+
Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.66.1
|
|
13
13
|
Keywords: package,executable,virtualenv,lock,freeze
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Intended Audience :: Developers
|