15
15
from pip ._internal .distributions import make_distribution_for_install_requirement
16
16
from pip ._internal .distributions .installed import InstalledDistribution
17
17
from pip ._internal .exceptions import (
18
+ CacheEntryTypeHashNotSupported ,
19
+ DependencyVcsHashNotSupported ,
18
20
DirectoryUrlHashUnsupported ,
19
21
HashMismatch ,
20
22
HashUnpinned ,
21
23
InstallationError ,
22
24
MetadataInconsistent ,
25
+ MutableVcsRefHashNotSupported ,
23
26
NetworkConnectionError ,
24
27
PreviousBuildDirError ,
25
28
VcsHashUnsupported ,
26
29
)
27
30
from pip ._internal .index .package_finder import PackageFinder
28
31
from pip ._internal .metadata import BaseDistribution , get_metadata_distribution
29
- from pip ._internal .models .direct_url import ArchiveInfo
32
+ from pip ._internal .models .direct_url import ArchiveInfo , VcsInfo
30
33
from pip ._internal .models .link import Link
31
34
from pip ._internal .models .wheel import Wheel
32
35
from pip ._internal .network .download import BatchDownloader , Downloader
41
44
direct_url_for_editable ,
42
45
direct_url_from_link ,
43
46
)
44
- from pip ._internal .utils .hashes import Hashes , MissingHashes
47
+ from pip ._internal .utils .hashes import Hashes , MissingHashes , VcsHashes
45
48
from pip ._internal .utils .logging import indent_log
46
49
from pip ._internal .utils .misc import (
47
50
display_path ,
@@ -72,10 +75,14 @@ def _get_prepared_distribution(
72
75
return abstract_dist .get_metadata_distribution ()
73
76
74
77
75
- def unpack_vcs_link (link : Link , location : str , verbosity : int ) -> None :
78
+ def unpack_vcs_link (
79
+ link : Link , location : str , verbosity : int , hashes : Optional [Hashes ] = None
80
+ ) -> None :
76
81
vcs_backend = vcs .get_backend_for_scheme (link .scheme )
77
82
assert vcs_backend is not None
78
83
vcs_backend .unpack (location , url = hide_url (link .url ), verbosity = verbosity )
84
+ if hashes and not vcs_backend .is_immutable_rev_checkout (link .url , location ):
85
+ raise MutableVcsRefHashNotSupported ()
79
86
80
87
81
88
class File :
@@ -152,7 +159,7 @@ def unpack_url(
152
159
"""
153
160
# non-editable vcs urls
154
161
if link .is_vcs :
155
- unpack_vcs_link (link , location , verbosity = verbosity )
162
+ unpack_vcs_link (link , location , verbosity = verbosity , hashes = hashes )
156
163
return None
157
164
158
165
assert not link .is_existing_dir ()
@@ -335,6 +342,14 @@ def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes:
335
342
# and raise some more informative errors than otherwise.
336
343
# (For example, we can raise VcsHashUnsupported for a VCS URL
337
344
# rather than HashMissing.)
345
+
346
+ # Check that --hash is not used with VCS and local directories direct URLs.
347
+ if req .original_link :
348
+ if req .original_link .is_vcs and req .hashes (trust_internet = False ):
349
+ raise VcsHashUnsupported ()
350
+ if req .original_link .is_existing_dir () and req .hashes (trust_internet = False ):
351
+ raise DirectoryUrlHashUnsupported ()
352
+
338
353
if not self .require_hashes :
339
354
return req .hashes (trust_internet = True )
340
355
@@ -343,7 +358,9 @@ def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes:
343
358
# report less-useful error messages for unhashable
344
359
# requirements, complaining that there's no hash provided.
345
360
if req .link .is_vcs :
346
- raise VcsHashUnsupported ()
361
+ if not req .user_supplied :
362
+ raise DependencyVcsHashNotSupported ()
363
+ return VcsHashes ()
347
364
if req .link .is_existing_dir ():
348
365
raise DirectoryUrlHashUnsupported ()
349
366
@@ -559,24 +576,33 @@ def _prepare_linked_requirement(
559
576
assert link .is_file
560
577
# We need to verify hashes, and we have found the requirement in the cache
561
578
# of locally built wheels.
562
- if (
563
- isinstance (req .download_info .info , ArchiveInfo )
564
- and req .download_info .info .hashes
565
- and hashes .has_one_of (req .download_info .info .hashes )
566
- ):
567
- # At this point we know the requirement was built from a hashable source
568
- # artifact, and we verified that the cache entry's hash of the original
569
- # artifact matches one of the hashes we expect. We don't verify hashes
570
- # against the cached wheel, because the wheel is not the original.
579
+ if isinstance (req .download_info .info , ArchiveInfo ):
580
+ if req .download_info .info .hashes and hashes .has_one_of (
581
+ req .download_info .info .hashes
582
+ ):
583
+ # At this point we know the requirement was built from a hashable
584
+ # source artifact, and we verified that the cache entry's hash of
585
+ # the original artifact matches one of the hashes we expect. We
586
+ # don't verify hashes against the cached wheel, because the wheel is
587
+ # not the original.
588
+ hashes = None
589
+ else :
590
+ logger .warning (
591
+ "The hashes of the source archive found in cache entry "
592
+ "don't match, ignoring cached built wheel "
593
+ "and re-downloading source."
594
+ )
595
+ req .link = req .cached_wheel_source_link
596
+ link = req .link
597
+ elif isinstance (req .download_info .info , VcsInfo ):
598
+ if not req .user_supplied :
599
+ raise DependencyVcsHashNotSupported ()
600
+ # Don't verify hashes against the cached wheel: if it is in cache,
601
+ # it means it was built from a URL referencing an immutable commit
602
+ # hash.
571
603
hashes = None
572
604
else :
573
- logger .warning (
574
- "The hashes of the source archive found in cache entry "
575
- "don't match, ignoring cached built wheel "
576
- "and re-downloading source."
577
- )
578
- req .link = req .cached_wheel_source_link
579
- link = req .link
605
+ raise CacheEntryTypeHashNotSupported ()
580
606
581
607
self ._ensure_link_req_src_dir (req , parallel_builds )
582
608
0 commit comments