Skip to content

Commit

Permalink
Add SHA256 hash of .whl as info output
Browse files Browse the repository at this point in the history
Currently I'm trying to debug some issues with what appear to be
corrupt wheels.  It would be very useful to see what pip thought the
state of things was as it wrote the wheel output; if a final corrupt
distributed file is then different to what pip has saved in its build
logs, you know the problem is somewhere after pip but before
distribution.

Currently we get a log of the initial creation, then the stamp when it
gets moved in the final output location, e.g.:

 creating '/tmp/pip-wheel-71CpBe/foo-1.2.3-py2.py3-none-any.whl
 ...
 Stored in directory: /opt/wheel/workspace

A lot happens in between this, so my suggestion is we add the final
output file and it's hash before the "Stored in directory:", e.g. you
now see:

 Building wheels for collected packages: simple
   Running setup.py bdist_wheel for simple: started
   Running setup.py bdist_wheel for simple: finished with status 'done'
   Finished: simple-3.0-py3-none-any.whl sha256=39005a57a6327972575072af82e11d0817439fe6a069381f6f2a123a8c0bf1cf
   Stored in directory: /tmp/pytest-of-iwienand/pytest-18/test_pip_wheel_success0/workspace/scratch
 Successfully built simple

Despite the hash being fairly important for things like
--require-hashes, AFAICS the final hash is not put in the logs at all
currently, so I think this is generically helpful.
  • Loading branch information
ianw committed May 6, 2019
1 parent cd403c6 commit 4e8b6e9
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
2 changes: 2 additions & 0 deletions news/5908.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Wheel builds will output the final filename and SHA256 hash of .whl
files as an info log entry.
14 changes: 12 additions & 2 deletions src/pip/_internal/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,22 @@ def normpath(src, p):
return os.path.relpath(src, p).replace(os.path.sep, '/')


def rehash(path, blocksize=1 << 20):
# type: (str, int) -> Tuple[str, str]
def hash_file(path, blocksize=1 << 20):
# type: (str, int) -> Tuple[Any, str]
"""Return (hash, length) for path using hashlib.sha256()"""
h = hashlib.sha256()
length = 0
with open(path, 'rb') as f:
for block in read_chunks(f, size=blocksize):
length += len(block)
h.update(block)
return (h, str(length)) # type: ignore


def rehash(path, blocksize=1 << 20):
# type: (str, int) -> Tuple[str, str]
"""Return (encoded_digest, length) for path using hashlib.sha256()"""
h, length = hash_file(path, blocksize)
digest = 'sha256=' + urlsafe_b64encode(
h.digest()
).decode('latin1').rstrip('=')
Expand Down Expand Up @@ -885,7 +892,10 @@ def _build_one_inside_env(self, req, output_dir, python_tag=None):
wheel_name = os.path.basename(wheel_path)
dest_path = os.path.join(output_dir, wheel_name)
try:
wheel_hash, _ = hash_file(wheel_path)
shutil.move(wheel_path, dest_path)
logger.info('Finished: %s sha256=%s',
wheel_name, wheel_hash.hexdigest())
logger.info('Stored in directory: %s', output_dir)
return dest_path
except Exception:
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/test_wheel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""'pip wheel' tests"""
import os
import re
from os.path import exists

import pytest
Expand Down Expand Up @@ -48,6 +49,9 @@ def test_pip_wheel_success(script, data):
)
wheel_file_name = 'simple-3.0-py%s-none-any.whl' % pyversion[0]
wheel_file_path = script.scratch / wheel_file_name
assert re.search(
"Finished: %s sha256=[A-Fa-f0-9]{64}" % re.escape(wheel_file_name),
result.stdout)
assert wheel_file_path in result.files_created, result.stdout
assert "Successfully built simple" in result.stdout, result.stdout

Expand Down

0 comments on commit 4e8b6e9

Please sign in to comment.