pex 2.63.0__py2.py3-none-any.whl → 2.64.0__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/cli/commands/lock.py +15 -0
- pex/dist_metadata.py +36 -9
- pex/docs/html/_pagefind/fragment/{en_f2578bc.pf_fragment → en_3046a3a.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_3f5cca9.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_5f2da5c.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_7350892.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/{en_66c5113.pf_fragment → en_ac9b982.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_d158da6.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_e575d34.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_fca878d.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_23c894e.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_86ab41ad5d.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/pip/tool.py +84 -11
- pex/pip/vcs.py +42 -25
- pex/resolve/lock_downloader.py +0 -1
- pex/resolve/locked_resolve.py +11 -11
- pex/resolve/locker.py +98 -18
- pex/resolve/lockfile/create.py +157 -27
- pex/resolve/lockfile/updater.py +11 -0
- pex/resolver.py +201 -4
- pex/version.py +1 -1
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/METADATA +4 -4
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/RECORD +38 -38
- pex/docs/html/_pagefind/fragment/en_6c6ecbd.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_6c77f9b.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_71b5a8a.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_8762fc9.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a55bc27.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_c87eb0d.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_b6cc89e.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind.en_5515c79d6d.pf_meta +0 -0
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/WHEEL +0 -0
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/entry_points.txt +0 -0
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/licenses/LICENSE +0 -0
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/pylock/pylock.toml +0 -0
- {pex-2.63.0.dist-info → pex-2.64.0.dist-info}/top_level.txt +0 -0
pex/pip/tool.py
CHANGED
|
@@ -491,9 +491,7 @@ class Pip(object):
|
|
|
491
491
|
# since Pip relies upon `shutil.move` which is only atomic when `os.rename` can be used.
|
|
492
492
|
# See https://github.com/pex-tool/pex/issues/1776 for an example of the issues non-atomic
|
|
493
493
|
# moves lead to in the `pip wheel` case.
|
|
494
|
-
|
|
495
|
-
safe_mkdir(pip_tmpdir)
|
|
496
|
-
extra_env.update(TMPDIR=pip_tmpdir)
|
|
494
|
+
extra_env.update(TMPDIR=safe_mkdtemp(dir=safe_mkdir(self.cache_dir), prefix=".tmp."))
|
|
497
495
|
|
|
498
496
|
with ENV.strip().patch(
|
|
499
497
|
PEX_ROOT=ENV.PEX_ROOT,
|
|
@@ -584,6 +582,47 @@ class Pip(object):
|
|
|
584
582
|
if not build_configuration.build_isolation:
|
|
585
583
|
yield "--no-build-isolation"
|
|
586
584
|
|
|
585
|
+
def spawn_report(
|
|
586
|
+
self,
|
|
587
|
+
report_path, # type: str
|
|
588
|
+
requirements=None, # type: Optional[Iterable[str]]
|
|
589
|
+
requirement_files=None, # type: Optional[Iterable[str]]
|
|
590
|
+
constraint_files=None, # type: Optional[Iterable[str]]
|
|
591
|
+
allow_prereleases=False, # type: bool
|
|
592
|
+
transitive=True, # type: bool
|
|
593
|
+
target=None, # type: Optional[Target]
|
|
594
|
+
package_index_configuration=None, # type: Optional[PackageIndexConfiguration]
|
|
595
|
+
build_configuration=BuildConfiguration(), # type: BuildConfiguration
|
|
596
|
+
observer=None, # type: Optional[DownloadObserver]
|
|
597
|
+
dependency_configuration=DependencyConfiguration(), # type: DependencyConfiguration
|
|
598
|
+
universal_target=None, # type: Optional[UniversalTarget]
|
|
599
|
+
log=None, # type: Optional[str]
|
|
600
|
+
):
|
|
601
|
+
# type: (...) -> Job
|
|
602
|
+
report_cmd = [
|
|
603
|
+
"install",
|
|
604
|
+
"--no-clean",
|
|
605
|
+
"--dry-run",
|
|
606
|
+
"--ignore-installed",
|
|
607
|
+
"--report",
|
|
608
|
+
report_path,
|
|
609
|
+
]
|
|
610
|
+
return self._spawn_install_compatible_command(
|
|
611
|
+
cmd=report_cmd,
|
|
612
|
+
requirements=requirements,
|
|
613
|
+
requirement_files=requirement_files,
|
|
614
|
+
constraint_files=constraint_files,
|
|
615
|
+
allow_prereleases=allow_prereleases,
|
|
616
|
+
transitive=transitive,
|
|
617
|
+
target=target,
|
|
618
|
+
package_index_configuration=package_index_configuration,
|
|
619
|
+
build_configuration=build_configuration,
|
|
620
|
+
observer=observer,
|
|
621
|
+
dependency_configuration=dependency_configuration,
|
|
622
|
+
universal_target=universal_target,
|
|
623
|
+
log=log,
|
|
624
|
+
)
|
|
625
|
+
|
|
587
626
|
def spawn_download_distributions(
|
|
588
627
|
self,
|
|
589
628
|
download_dir, # type: str
|
|
@@ -601,32 +640,66 @@ class Pip(object):
|
|
|
601
640
|
log=None, # type: Optional[str]
|
|
602
641
|
):
|
|
603
642
|
# type: (...) -> Job
|
|
604
|
-
target = target or targets.current()
|
|
605
643
|
|
|
606
644
|
download_cmd = ["download", "--dest", download_dir]
|
|
645
|
+
return self._spawn_install_compatible_command(
|
|
646
|
+
cmd=download_cmd,
|
|
647
|
+
requirements=requirements,
|
|
648
|
+
requirement_files=requirement_files,
|
|
649
|
+
constraint_files=constraint_files,
|
|
650
|
+
allow_prereleases=allow_prereleases,
|
|
651
|
+
transitive=transitive,
|
|
652
|
+
target=target,
|
|
653
|
+
package_index_configuration=package_index_configuration,
|
|
654
|
+
build_configuration=build_configuration,
|
|
655
|
+
observer=observer,
|
|
656
|
+
dependency_configuration=dependency_configuration,
|
|
657
|
+
universal_target=universal_target,
|
|
658
|
+
log=log,
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
def _spawn_install_compatible_command(
|
|
662
|
+
self,
|
|
663
|
+
cmd, # type: List[str]
|
|
664
|
+
requirements=None, # type: Optional[Iterable[str]]
|
|
665
|
+
requirement_files=None, # type: Optional[Iterable[str]]
|
|
666
|
+
constraint_files=None, # type: Optional[Iterable[str]]
|
|
667
|
+
allow_prereleases=False, # type: bool
|
|
668
|
+
transitive=True, # type: bool
|
|
669
|
+
target=None, # type: Optional[Target]
|
|
670
|
+
package_index_configuration=None, # type: Optional[PackageIndexConfiguration]
|
|
671
|
+
build_configuration=BuildConfiguration(), # type: BuildConfiguration
|
|
672
|
+
observer=None, # type: Optional[DownloadObserver]
|
|
673
|
+
dependency_configuration=DependencyConfiguration(), # type: DependencyConfiguration
|
|
674
|
+
universal_target=None, # type: Optional[UniversalTarget]
|
|
675
|
+
log=None, # type: Optional[str]
|
|
676
|
+
):
|
|
677
|
+
# type: (...) -> Job
|
|
678
|
+
target = target or targets.current()
|
|
679
|
+
|
|
607
680
|
extra_env = {} # type: Dict[str, str]
|
|
608
681
|
pex_extra_sys_path = [] # type: List[str]
|
|
609
682
|
|
|
610
|
-
|
|
683
|
+
cmd.extend(self._iter_build_configuration_options(build_configuration))
|
|
611
684
|
if not build_configuration.build_isolation:
|
|
612
685
|
pex_extra_sys_path.extend(sys.path)
|
|
613
686
|
|
|
614
687
|
if allow_prereleases:
|
|
615
|
-
|
|
688
|
+
cmd.append("--pre")
|
|
616
689
|
|
|
617
690
|
if not transitive:
|
|
618
|
-
|
|
691
|
+
cmd.append("--no-deps")
|
|
619
692
|
|
|
620
693
|
if requirement_files:
|
|
621
694
|
for requirement_file in requirement_files:
|
|
622
|
-
|
|
695
|
+
cmd.extend(["--requirement", requirement_file])
|
|
623
696
|
|
|
624
697
|
if constraint_files:
|
|
625
698
|
for constraint_file in constraint_files:
|
|
626
|
-
|
|
699
|
+
cmd.extend(["--constraint", constraint_file])
|
|
627
700
|
|
|
628
701
|
if requirements:
|
|
629
|
-
|
|
702
|
+
cmd.extend(requirements)
|
|
630
703
|
|
|
631
704
|
foreign_platform_observer = foreign_platform.patch(target)
|
|
632
705
|
if (
|
|
@@ -722,7 +795,7 @@ class Pip(object):
|
|
|
722
795
|
tailer.stop()
|
|
723
796
|
|
|
724
797
|
command, process = self._spawn_pip_isolated(
|
|
725
|
-
|
|
798
|
+
cmd,
|
|
726
799
|
package_index_configuration=package_index_configuration,
|
|
727
800
|
interpreter=target.get_interpreter(),
|
|
728
801
|
log=log,
|
pex/pip/vcs.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
|
+
import glob
|
|
6
7
|
import os
|
|
7
8
|
import re
|
|
8
9
|
|
|
@@ -60,7 +61,6 @@ def fingerprint_downloaded_vcs_archive(
|
|
|
60
61
|
project_name, # type: str
|
|
61
62
|
version, # type: str
|
|
62
63
|
vcs, # type: VCS.Value
|
|
63
|
-
subdirectory=None, # type: Optional[str]
|
|
64
64
|
):
|
|
65
65
|
# type: (...) -> Tuple[Fingerprint, str]
|
|
66
66
|
|
|
@@ -70,7 +70,7 @@ def fingerprint_downloaded_vcs_archive(
|
|
|
70
70
|
)
|
|
71
71
|
)
|
|
72
72
|
digest = Sha256()
|
|
73
|
-
digest_vcs_archive(archive_path=archive_path, vcs=vcs, digest=digest
|
|
73
|
+
digest_vcs_archive(archive_path=archive_path, vcs=vcs, digest=digest)
|
|
74
74
|
return Fingerprint.from_digest(digest), archive_path
|
|
75
75
|
|
|
76
76
|
|
|
@@ -78,36 +78,53 @@ def digest_vcs_archive(
|
|
|
78
78
|
archive_path, # type: str
|
|
79
79
|
vcs, # type: VCS.Value
|
|
80
80
|
digest, # type: HintedDigest
|
|
81
|
-
subdirectory=None, # type: Optional[str]
|
|
82
81
|
):
|
|
83
82
|
# type: (...) -> None
|
|
84
83
|
|
|
85
84
|
# All VCS requirements are prepared as zip archives as encoded in:
|
|
86
|
-
# `pip._internal.req.req_install.InstallRequirement.archive
|
|
85
|
+
# `pip._internal.req.req_install.InstallRequirement.archive` and the archive is already offset
|
|
86
|
+
# by a subdirectory (if any).
|
|
87
87
|
with TRACER.timed(
|
|
88
88
|
"Digesting {archive} {vcs} archive".format(archive=os.path.basename(archive_path), vcs=vcs)
|
|
89
89
|
), temporary_dir() as chroot, open_zip(archive_path) as archive:
|
|
90
|
+
# TODO(John Sirois): Consider implementing zip_hash to avoid the extractall.
|
|
90
91
|
archive.extractall(chroot)
|
|
91
92
|
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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)
|
|
93
|
+
# The zip archives created by Pip have a single project name top-level directory housing
|
|
94
|
+
# the full clone. We look for that to get a consistent clone hash with a bare clone.
|
|
95
|
+
listing = glob.glob(os.path.join(chroot, "*"))
|
|
96
|
+
if len(listing) == 1 and os.path.isdir(listing[0]):
|
|
97
|
+
chroot = listing[0]
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
digest_vcs_repo(repo_path=chroot, vcs=vcs, digest=digest)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def digest_vcs_repo(
|
|
103
|
+
repo_path, # type: str
|
|
104
|
+
vcs, # type: VCS.Value
|
|
105
|
+
digest, # type: HintedDigest
|
|
106
|
+
subdirectory=None, # type: Optional[str]
|
|
107
|
+
):
|
|
108
|
+
# type: (...) -> None
|
|
109
|
+
|
|
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
|
+
hashing.dir_hash(
|
|
122
|
+
directory=os.path.join(repo_path, subdirectory) if subdirectory else repo_path,
|
|
123
|
+
digest=digest,
|
|
124
|
+
dir_filter=(
|
|
125
|
+
lambda dir_path: (
|
|
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),
|
|
130
|
+
)
|
pex/resolve/lock_downloader.py
CHANGED
|
@@ -157,7 +157,6 @@ class VCSArtifactDownloadManager(DownloadManager[VCSArtifact]):
|
|
|
157
157
|
archive_path=local_distribution.path,
|
|
158
158
|
vcs=artifact.vcs,
|
|
159
159
|
digest=digest,
|
|
160
|
-
subdirectory=artifact.subdirectory,
|
|
161
160
|
)
|
|
162
161
|
shutil.move(local_distribution.path, os.path.join(dest_dir, filename))
|
|
163
162
|
return filename
|
pex/resolve/locked_resolve.py
CHANGED
|
@@ -12,7 +12,7 @@ from functools import total_ordering
|
|
|
12
12
|
from pex.artifact_url import VCS, ArtifactURL, Fingerprint, VCSScheme
|
|
13
13
|
from pex.common import pluralize
|
|
14
14
|
from pex.dependency_configuration import DependencyConfiguration
|
|
15
|
-
from pex.dist_metadata import
|
|
15
|
+
from pex.dist_metadata import ProjectMetadata, Requirement, is_sdist, is_wheel
|
|
16
16
|
from pex.enum import Enum
|
|
17
17
|
from pex.exceptions import production_assert
|
|
18
18
|
from pex.interpreter_constraints import InterpreterConstraint
|
|
@@ -660,7 +660,7 @@ class LockedResolve(object):
|
|
|
660
660
|
def create(
|
|
661
661
|
cls,
|
|
662
662
|
resolved_requirements, # type: Iterable[ResolvedRequirement]
|
|
663
|
-
|
|
663
|
+
project_metadatas, # type: Iterable[ProjectMetadata]
|
|
664
664
|
fingerprinter, # type: Fingerprinter
|
|
665
665
|
platform_tag=None, # type: Optional[tags.Tag]
|
|
666
666
|
marker=None, # type: Optional[Marker]
|
|
@@ -703,21 +703,21 @@ class LockedResolve(object):
|
|
|
703
703
|
editable=partial_artifact.editable,
|
|
704
704
|
)
|
|
705
705
|
|
|
706
|
-
|
|
706
|
+
project_metadata_by_pin = {
|
|
707
707
|
Pin(dist_info.project_name, dist_info.version): dist_info
|
|
708
|
-
for dist_info in
|
|
708
|
+
for dist_info in project_metadatas
|
|
709
709
|
}
|
|
710
710
|
locked_requirements = []
|
|
711
711
|
for resolved_requirement in resolved_requirements:
|
|
712
|
-
|
|
713
|
-
if
|
|
712
|
+
project_metadata = project_metadata_by_pin.get(resolved_requirement.pin)
|
|
713
|
+
if project_metadata is None:
|
|
714
714
|
raise ValueError(
|
|
715
|
-
"No
|
|
716
|
-
"Given
|
|
715
|
+
"No project metadata found for {project}.\n"
|
|
716
|
+
"Given project metadata for:\n"
|
|
717
717
|
"{projects}".format(
|
|
718
718
|
project=resolved_requirement.pin.as_requirement(),
|
|
719
719
|
projects="\n".join(
|
|
720
|
-
sorted(str(pin.as_requirement()) for pin in
|
|
720
|
+
sorted(str(pin.as_requirement()) for pin in project_metadata_by_pin)
|
|
721
721
|
),
|
|
722
722
|
)
|
|
723
723
|
)
|
|
@@ -725,8 +725,8 @@ class LockedResolve(object):
|
|
|
725
725
|
LockedRequirement.create(
|
|
726
726
|
pin=resolved_requirement.pin,
|
|
727
727
|
artifact=resolve_fingerprint(resolved_requirement.artifact),
|
|
728
|
-
requires_dists=
|
|
729
|
-
requires_python=
|
|
728
|
+
requires_dists=project_metadata.requires_dists,
|
|
729
|
+
requires_python=project_metadata.requires_python,
|
|
730
730
|
additional_artifacts=(
|
|
731
731
|
resolve_fingerprint(artifact)
|
|
732
732
|
for artifact in resolved_requirement.additional_artifacts
|
pex/resolve/locker.py
CHANGED
|
@@ -16,11 +16,12 @@ from pex.dist_metadata import ProjectNameAndVersion, Requirement
|
|
|
16
16
|
from pex.hashing import Sha256
|
|
17
17
|
from pex.orderedset import OrderedSet
|
|
18
18
|
from pex.pep_440 import Version
|
|
19
|
+
from pex.pep_503 import ProjectName
|
|
19
20
|
from pex.pip import foreign_platform
|
|
20
21
|
from pex.pip.download_observer import Patch, PatchSet
|
|
21
22
|
from pex.pip.local_project import digest_local_project
|
|
22
23
|
from pex.pip.log_analyzer import LogAnalyzer
|
|
23
|
-
from pex.pip.vcs import fingerprint_downloaded_vcs_archive
|
|
24
|
+
from pex.pip.vcs import digest_vcs_repo, fingerprint_downloaded_vcs_archive
|
|
24
25
|
from pex.pip.version import PipVersionValue
|
|
25
26
|
from pex.requirements import LocalProjectRequirement, VCSRequirement
|
|
26
27
|
from pex.resolve.locked_resolve import LockStyle
|
|
@@ -194,6 +195,7 @@ class AnalyzeError(Exception):
|
|
|
194
195
|
|
|
195
196
|
@attr.s(frozen=True)
|
|
196
197
|
class ArtifactBuildResult(object):
|
|
198
|
+
path = attr.ib() # type: str
|
|
197
199
|
url = attr.ib() # type: ArtifactURL
|
|
198
200
|
pin = attr.ib() # type: Pin
|
|
199
201
|
|
|
@@ -211,17 +213,18 @@ class ArtifactBuildObserver(object):
|
|
|
211
213
|
# type: (str) -> Optional[ArtifactBuildResult]
|
|
212
214
|
|
|
213
215
|
match = re.search(
|
|
214
|
-
r"Source in
|
|
216
|
+
r"Source in (?P<path>.+) has version (?P<version>\S+), which satisfies requirement "
|
|
215
217
|
r"(?P<requirement>.+) .*from {url}".format(url=re.escape(self._artifact_url.raw_url)),
|
|
216
218
|
line,
|
|
217
219
|
)
|
|
218
220
|
if not match:
|
|
219
221
|
return None
|
|
220
222
|
|
|
223
|
+
path = match.group("path")
|
|
221
224
|
version = Version(match.group("version"))
|
|
222
225
|
requirement = Requirement.parse(match.group("requirement"))
|
|
223
226
|
pin = Pin(project_name=requirement.project_name, version=version)
|
|
224
|
-
return ArtifactBuildResult(url=self._artifact_url, pin=pin)
|
|
227
|
+
return ArtifactBuildResult(path=path, url=self._artifact_url, pin=pin)
|
|
225
228
|
|
|
226
229
|
|
|
227
230
|
class Locker(LogAnalyzer):
|
|
@@ -234,12 +237,14 @@ class Locker(LogAnalyzer):
|
|
|
234
237
|
download_dir, # type: str
|
|
235
238
|
fingerprint_service=None, # type: Optional[FingerprintService]
|
|
236
239
|
pip_version=None, # type: Optional[PipVersionValue]
|
|
240
|
+
lock_is_via_pip_download=False, # type: bool
|
|
237
241
|
):
|
|
238
242
|
# type: (...) -> None
|
|
239
243
|
|
|
240
244
|
self._target = target
|
|
241
245
|
self._vcs_url_manager = VCSURLManager.create(root_requirements)
|
|
242
246
|
self._pip_version = pip_version
|
|
247
|
+
self._lock_is_via_pip_download = lock_is_via_pip_download
|
|
243
248
|
self._resolver = resolver
|
|
244
249
|
self._lock_style = lock_style
|
|
245
250
|
self._download_dir = download_dir
|
|
@@ -357,19 +362,18 @@ class Locker(LogAnalyzer):
|
|
|
357
362
|
return self.Continue()
|
|
358
363
|
|
|
359
364
|
build_result = self._artifact_build_observer.build_result(line)
|
|
360
|
-
|
|
365
|
+
source_fingerprint = None # type: Optional[Fingerprint]
|
|
366
|
+
verified = False
|
|
367
|
+
commit_id = None # type: Optional[str]
|
|
368
|
+
editable = False
|
|
369
|
+
if build_result and self._lock_is_via_pip_download:
|
|
361
370
|
artifact_url = build_result.url
|
|
362
|
-
source_fingerprint = None # type: Optional[Fingerprint]
|
|
363
|
-
verified = False
|
|
364
|
-
commit_id = None # type: Optional[str]
|
|
365
|
-
editable = False
|
|
366
371
|
if isinstance(artifact_url.scheme, VCSScheme):
|
|
367
372
|
source_fingerprint, archive_path = fingerprint_downloaded_vcs_archive(
|
|
368
373
|
download_dir=self._download_dir,
|
|
369
374
|
project_name=str(build_result.pin.project_name),
|
|
370
375
|
version=str(build_result.pin.version),
|
|
371
376
|
vcs=artifact_url.scheme.vcs,
|
|
372
|
-
subdirectory=artifact_url.subdirectory,
|
|
373
377
|
)
|
|
374
378
|
verified = True
|
|
375
379
|
selected_path = os.path.basename(archive_path)
|
|
@@ -378,8 +382,8 @@ class Locker(LogAnalyzer):
|
|
|
378
382
|
)
|
|
379
383
|
self._selected_path_to_pin[selected_path] = build_result.pin
|
|
380
384
|
|
|
381
|
-
vcs, _, vcs_url =
|
|
382
|
-
if "@" in
|
|
385
|
+
vcs, _, vcs_url = artifact_url.raw_url.partition("+")
|
|
386
|
+
if "@" in artifact_url.path:
|
|
383
387
|
vcs_url, _, _ = vcs_url.rpartition("@")
|
|
384
388
|
commit_id = self._commit_ids.pop(vcs_url, None)
|
|
385
389
|
elif isinstance(artifact_url.scheme, ArchiveScheme.Value):
|
|
@@ -425,6 +429,74 @@ class Locker(LogAnalyzer):
|
|
|
425
429
|
additional_artifacts = self._links[build_result.pin]
|
|
426
430
|
additional_artifacts.pop(artifact_url, None)
|
|
427
431
|
|
|
432
|
+
self._resolved_requirements[build_result.pin] = ResolvedRequirement(
|
|
433
|
+
pin=build_result.pin,
|
|
434
|
+
artifact=PartialArtifact(
|
|
435
|
+
url=artifact_url,
|
|
436
|
+
fingerprint=source_fingerprint,
|
|
437
|
+
verified=verified,
|
|
438
|
+
commit_id=commit_id,
|
|
439
|
+
editable=editable,
|
|
440
|
+
),
|
|
441
|
+
additional_artifacts=tuple(additional_artifacts.values()),
|
|
442
|
+
)
|
|
443
|
+
elif build_result:
|
|
444
|
+
artifact_url = build_result.url
|
|
445
|
+
if isinstance(artifact_url.scheme, VCSScheme):
|
|
446
|
+
digest = Sha256()
|
|
447
|
+
digest_vcs_repo(
|
|
448
|
+
repo_path=build_result.path,
|
|
449
|
+
vcs=artifact_url.scheme.vcs,
|
|
450
|
+
digest=digest,
|
|
451
|
+
subdirectory=artifact_url.subdirectory,
|
|
452
|
+
)
|
|
453
|
+
source_fingerprint = Fingerprint.from_digest(digest)
|
|
454
|
+
verified = True # noqa
|
|
455
|
+
vcs, _, vcs_url = artifact_url.raw_url.partition("+")
|
|
456
|
+
if "@" in artifact_url.path:
|
|
457
|
+
vcs_url, _, _ = vcs_url.rpartition("@")
|
|
458
|
+
commit_id = self._commit_ids.pop(vcs_url, None)
|
|
459
|
+
elif isinstance(artifact_url.scheme, ArchiveScheme.Value):
|
|
460
|
+
source_archive_path = build_result.path
|
|
461
|
+
# If Pip resolves the artifact from its own cache, we will not find it in the
|
|
462
|
+
# download dir for this run; so guard against that. In this case the existing
|
|
463
|
+
# machinery that finalizes a locks missing fingerprints will download the
|
|
464
|
+
# artifact and hash it.
|
|
465
|
+
if os.path.isfile(source_archive_path):
|
|
466
|
+
digest = Sha256()
|
|
467
|
+
hashing.file_hash(source_archive_path, digest)
|
|
468
|
+
source_fingerprint = Fingerprint.from_digest(digest)
|
|
469
|
+
verified = True
|
|
470
|
+
elif "file" == artifact_url.scheme:
|
|
471
|
+
digest = Sha256()
|
|
472
|
+
if os.path.isfile(artifact_url.path):
|
|
473
|
+
hashing.file_hash(artifact_url.path, digest)
|
|
474
|
+
self._selected_path_to_pin[
|
|
475
|
+
os.path.basename(artifact_url.path)
|
|
476
|
+
] = build_result.pin
|
|
477
|
+
else:
|
|
478
|
+
digest_local_project(
|
|
479
|
+
directory=artifact_url.path,
|
|
480
|
+
digest=digest,
|
|
481
|
+
pip_version=self._pip_version,
|
|
482
|
+
target=self._target,
|
|
483
|
+
resolver=self._resolver,
|
|
484
|
+
)
|
|
485
|
+
self._local_projects.add(artifact_url.path)
|
|
486
|
+
self._saved.add(build_result.pin)
|
|
487
|
+
editable = artifact_url.path in self._editable_projects
|
|
488
|
+
source_fingerprint = Fingerprint.from_digest(digest)
|
|
489
|
+
verified = True
|
|
490
|
+
else:
|
|
491
|
+
raise AnalyzeError(
|
|
492
|
+
"Unexpected scheme {scheme!r} for artifact at {url}".format(
|
|
493
|
+
scheme=artifact_url.scheme, url=artifact_url
|
|
494
|
+
)
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
additional_artifacts = self._links[build_result.pin]
|
|
498
|
+
additional_artifacts.pop(artifact_url, None)
|
|
499
|
+
|
|
428
500
|
self._resolved_requirements[build_result.pin] = ResolvedRequirement(
|
|
429
501
|
pin=build_result.pin,
|
|
430
502
|
artifact=PartialArtifact(
|
|
@@ -506,13 +578,21 @@ class Locker(LogAnalyzer):
|
|
|
506
578
|
)
|
|
507
579
|
return self.Continue()
|
|
508
580
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
581
|
+
if self._lock_is_via_pip_download:
|
|
582
|
+
match = re.search(r"Saved (?P<file_path>.+)$", line)
|
|
583
|
+
if match:
|
|
584
|
+
saved_path = match.group("file_path")
|
|
585
|
+
build_result_pin = self._selected_path_to_pin.get(os.path.basename(saved_path))
|
|
586
|
+
if build_result_pin:
|
|
587
|
+
self._saved.add(build_result_pin)
|
|
588
|
+
return self.Continue()
|
|
589
|
+
else:
|
|
590
|
+
match = re.search(r"Would install (?P<pnavs>.+)$", line)
|
|
591
|
+
if match:
|
|
592
|
+
for pnav in match.group("pnavs").split():
|
|
593
|
+
project_name, _, version = pnav.rpartition("-")
|
|
594
|
+
self._saved.add(Pin(ProjectName(project_name), Version(version)))
|
|
595
|
+
return self.Continue()
|
|
516
596
|
|
|
517
597
|
if self._lock_style in (LockStyle.SOURCES, LockStyle.UNIVERSAL):
|
|
518
598
|
match = re.search(r"Found link (?P<url>\S+)(?: \(from .*\))?, version: ", line)
|