37
37
from pip ._internal .req .req_install import InstallRequirement
38
38
from pip ._internal .utils .hashes import Hashes , MissingHashes
39
39
from pip ._internal .utils .logging import indent_log
40
- from pip ._internal .utils .misc import display_path , hide_url , is_installable_dir
40
+ from pip ._internal .utils .misc import (
41
+ display_path ,
42
+ hash_file ,
43
+ hide_url ,
44
+ is_installable_dir ,
45
+ )
41
46
from pip ._internal .utils .temp_dir import TempDirectory
42
47
from pip ._internal .utils .unpacking import unpack_file
43
48
from pip ._internal .vcs import vcs
@@ -98,7 +103,10 @@ def get_http_url(
98
103
99
104
100
105
def get_file_url (
101
- link : Link , download_dir : Optional [str ] = None , hashes : Optional [Hashes ] = None
106
+ link : Link ,
107
+ download_dir : Optional [str ] = None ,
108
+ hashes : Optional [Hashes ] = None ,
109
+ archive_hash : Optional [str ] = None ,
102
110
) -> File :
103
111
"""Get file and optionally check its hash."""
104
112
# If a download dir is specified, is the file already there and valid?
@@ -117,7 +125,13 @@ def get_file_url(
117
125
# hash in `hashes` matching: a URL-based or an option-based
118
126
# one; no internet-sourced hash will be in `hashes`.
119
127
if hashes :
120
- hashes .check_against_path (from_path )
128
+ if archive_hash :
129
+ # When we get a wheel from the cache, we don't check the file hash but
130
+ # rather compare expected hash against the hash of the original archive
131
+ # that was downloaded to build the cached wheel.
132
+ hashes .check_against_hash (archive_hash )
133
+ else :
134
+ hashes .check_against_path (from_path )
121
135
return File (from_path , None )
122
136
123
137
@@ -128,6 +142,7 @@ def unpack_url(
128
142
verbosity : int ,
129
143
download_dir : Optional [str ] = None ,
130
144
hashes : Optional [Hashes ] = None ,
145
+ archive_hash : Optional [str ] = None ,
131
146
) -> Optional [File ]:
132
147
"""Unpack link into location, downloading if required.
133
148
@@ -145,7 +160,9 @@ def unpack_url(
145
160
146
161
# file urls
147
162
if link .is_file :
148
- file = get_file_url (link , download_dir , hashes = hashes )
163
+ file = get_file_url (
164
+ link , download_dir , hashes = hashes , archive_hash = archive_hash
165
+ )
149
166
150
167
# http urls
151
168
else :
@@ -470,6 +487,7 @@ def _prepare_linked_requirement(
470
487
self .verbosity ,
471
488
self .download_dir ,
472
489
hashes ,
490
+ req .archive_hash ,
473
491
)
474
492
except NetworkConnectionError as exc :
475
493
raise InstallationError (
@@ -486,6 +504,12 @@ def _prepare_linked_requirement(
486
504
# preserve the file path on the requirement.
487
505
if local_file :
488
506
req .local_file_path = local_file .path
507
+ # Also compute and preserve the hash of the file we downloaded.
508
+ # Note: as an optimization we may use link.hash if it is a sha256,
509
+ # as we verify elsewhere that it matches the downloaded content.
510
+ # TODO Should we use hashes.FAVORITE_HASH type ?
511
+ hash = hash_file (local_file .path )[0 ].hexdigest ()
512
+ req .archive_hash = f"sha256={ hash } "
489
513
490
514
dist = _get_prepared_distribution (
491
515
req ,
0 commit comments