Skip to content

Commit

Permalink
Sort list of RECORD entries
Browse files Browse the repository at this point in the history
Without sorting, the 'installed' hash had entries in random order
that caused output to differ for every run.

See https://reproducible-builds.org/ for why this matters.

Sorting all entries to make testing easier.
  • Loading branch information
bmwiedemann committed Sep 7, 2018
1 parent 0d9c05e commit 34d4d1e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 3 deletions.
1 change: 1 addition & 0 deletions news/5525.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pip now ensures that the RECORD file is sorted when installing from a wheel file.
9 changes: 6 additions & 3 deletions src/pip/_internal/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,19 @@ def _get_script_text(entry):
with open_for_csv(temp_record, 'w+') as record_out:
reader = csv.reader(record_in)
writer = csv.writer(record_out)
outrows = []
for row in reader:
row[0] = installed.pop(row[0], row[0])
if row[0] in changed:
row[1], row[2] = rehash(row[0])
writer.writerow(row)
outrows.append(tuple(row))
for f in generated:
digest, length = rehash(f)
writer.writerow((normpath(f, lib_dir), digest, length))
outrows.append((normpath(f, lib_dir), digest, length))
for f in installed:
writer.writerow((installed[f], '', ''))
outrows.append((installed[f], '', ''))
for row in sorted(outrows):
writer.writerow(row)
shutil.move(temp_record, record)


Expand Down
17 changes: 17 additions & 0 deletions tests/functional/test_install_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,23 @@ def test_install_from_wheel_no_deps(script, data):
assert pkg_folder not in result.files_created


def test_wheel_record_lines_in_deterministic_order(script, data):
to_install = data.packages.join("simplewheel-1.0-py2.py3-none-any.whl")
result = script.pip('install', to_install)

dist_info_folder = script.site_packages / 'simplewheel-1.0.dist-info'
record_path = dist_info_folder / 'RECORD'

assert dist_info_folder in result.files_created, str(result)
assert record_path in result.files_created, str(result)

record_path = result.files_created[record_path].full
record_lines = [
p for p in Path(record_path).read_text().split('\n') if p
]
assert record_lines == sorted(record_lines)


@pytest.mark.network
def test_install_user_wheel(script, virtualenv, data, common_wheels):
"""
Expand Down

0 comments on commit 34d4d1e

Please sign in to comment.