Skip to content

Commit 17bf443

Browse files
author
Patrik Kopkan
committed
Add new option: pip wheel --save-wheel-names
1 parent b447f43 commit 17bf443

File tree

4 files changed

+141
-2
lines changed

4 files changed

+141
-2
lines changed

src/pip/_internal/commands/wheel.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ def __init__(self, *args, **kw):
9898
cmd_opts.add_option(cmdoptions.no_clean())
9999
cmd_opts.add_option(cmdoptions.require_hashes())
100100

101+
cmd_opts.add_option(
102+
'--save-wheel-names',
103+
dest='path_to_wheelnames',
104+
action='store',
105+
metavar='path',
106+
help=("Store the filenames of the built or downloaded wheels "
107+
"in a new file of given path. Filenames are separated "
108+
"by new line and file ends with new line"),
109+
)
110+
101111
index_opts = cmdoptions.make_option_group(
102112
cmdoptions.index_group,
103113
self.parser,
@@ -106,6 +116,28 @@ def __init__(self, *args, **kw):
106116
self.parser.insert_option_group(0, index_opts)
107117
self.parser.insert_option_group(0, cmd_opts)
108118

119+
def save_wheelnames(
120+
self,
121+
links_filenames,
122+
path_to_wheelnames,
123+
wheel_filenames,
124+
):
125+
if path_to_wheelnames is None:
126+
return
127+
128+
entries_to_save = wheel_filenames + links_filenames
129+
entries_to_save = [
130+
filename + '\n' for filename in entries_to_save
131+
if filename.endswith('whl')
132+
]
133+
try:
134+
with open(path_to_wheelnames, 'w') as f:
135+
f.writelines(entries_to_save)
136+
except EnvironmentError as e:
137+
logger.error('Cannot write to the given path: %s\n%s' %
138+
(path_to_wheelnames, e))
139+
raise
140+
109141
def run(self, options, args):
110142
# type: (Values, List[Any]) -> None
111143
cmdoptions.check_install_build_global(options)
@@ -159,10 +191,18 @@ def run(self, options, args):
159191
build_options=options.build_options or [],
160192
global_options=options.global_options or [],
161193
no_clean=options.no_clean,
194+
path_to_wheelnames=options.path_to_wheelnames
162195
)
163196
build_failures = wb.build(
164197
requirement_set.requirements.values(),
165198
)
199+
self.save_wheelnames(
200+
[req.link.filename for req in
201+
requirement_set.successfully_downloaded
202+
if req.link is not None],
203+
wb.path_to_wheelnames,
204+
wb.wheel_filenames,
205+
)
166206
if len(build_failures) != 0:
167207
raise CommandError(
168208
"Failed to build one or more wheels"

src/pip/_internal/wheel.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
if MYPY_CHECK_RUNNING:
5656
from typing import (
5757
Dict, List, Optional, Sequence, Mapping, Tuple, IO, Text, Any,
58-
Iterable, Callable,
58+
Iterable, Callable, Union,
5959
)
6060
from pip._vendor.packaging.requirements import Requirement
6161
from pip._internal.req.req_install import InstallRequirement
@@ -905,7 +905,8 @@ def __init__(
905905
build_options=None, # type: Optional[List[str]]
906906
global_options=None, # type: Optional[List[str]]
907907
check_binary_allowed=None, # type: Optional[BinaryAllowedPredicate]
908-
no_clean=False # type: bool
908+
no_clean=False, # type: bool
909+
path_to_wheelnames=None, # type: Optional[Union[bytes, Text]]
909910
):
910911
# type: (...) -> None
911912
if check_binary_allowed is None:
@@ -921,6 +922,10 @@ def __init__(
921922
self.global_options = global_options or []
922923
self.check_binary_allowed = check_binary_allowed
923924
self.no_clean = no_clean
925+
# path where to save built names of built wheels
926+
self.path_to_wheelnames = path_to_wheelnames
927+
# file names of built wheel names
928+
self.wheel_filenames = [] # type: List[Union[bytes, Text]]
924929

925930
def _build_one(self, req, output_dir, python_tag=None):
926931
"""Build one wheel.
@@ -1130,6 +1135,9 @@ def build(
11301135
)
11311136
if wheel_file:
11321137
build_success.append(req)
1138+
self.wheel_filenames.append(
1139+
os.path.relpath(wheel_file, output_dir)
1140+
)
11331141
if should_unpack:
11341142
# XXX: This is mildly duplicative with prepare_files,
11351143
# but not close enough to pull out to a single common

tests/functional/test_wheel.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""'pip wheel' tests"""
22
import os
33
import re
4+
import stat
45
from os.path import exists
56

67
import pytest
@@ -255,3 +256,65 @@ def test_legacy_wheels_are_not_confused_with_other_files(script, tmpdir, data):
255256
wheel_file_name = 'simplewheel-1.0-py%s-none-any.whl' % pyversion[0]
256257
wheel_file_path = script.scratch / wheel_file_name
257258
assert wheel_file_path in result.files_created, result.stdout
259+
260+
261+
def test_pip_option_save_wheel_name(script, data):
262+
"""Check if the option saves the filenames of built wheels
263+
"""
264+
script.pip(
265+
'wheel', '--no-index', '-f', data.find_links,
266+
'require_simple==1.0',
267+
'--save-wheel-name', 'wheelnames',
268+
)
269+
270+
wheel_file_names = [
271+
'require_simple-1.0-py%s-none-any.whl' % pyversion[0],
272+
'simple-3.0-py%s-none-any.whl' % pyversion[0],
273+
]
274+
wheelnames_path = script.scratch_path / 'wheelnames'
275+
with open(wheelnames_path, 'r') as wheelnames_file:
276+
wheelnames_entries = (wheelnames_file.read()).splitlines()
277+
assert wheel_file_names == wheelnames_entries
278+
279+
280+
def test_pip_option_save_wheel_name_Permission_error(script, data):
281+
282+
temp_file = script.base_path / 'scratch' / 'wheelnames'
283+
284+
wheel_file_names = [
285+
'require_simple-1.0-py%s-none-any.whl' % pyversion[0],
286+
'simple-3.0-py%s-none-any.whl' % pyversion[0],
287+
]
288+
289+
script.pip(
290+
'wheel', '--no-index', '-f', data.find_links,
291+
'require_simple==1.0',
292+
'--save-wheel-name', 'wheelnames',
293+
)
294+
os.chmod(temp_file, stat.S_IREAD)
295+
result = script.pip(
296+
'wheel', '--no-index', '-f', data.find_links,
297+
'require_simple==1.0',
298+
'--save-wheel-name', 'wheelnames', expect_error=True,
299+
)
300+
os.chmod(temp_file, stat.S_IREAD | stat.S_IWRITE)
301+
302+
assert "ERROR: Cannot write to the given path: wheelnames\n" \
303+
"[Errno 13] Permission denied: 'wheelnames'\n" in result.stderr
304+
305+
with open(temp_file) as f:
306+
result = f.read().splitlines()
307+
# check that file stays same
308+
assert result == wheel_file_names
309+
310+
311+
def test_pip_option_save_wheel_name_error_during_build(script, data):
312+
script.pip(
313+
'wheel', '--no-index', '--save-wheel-name', 'wheelnames',
314+
'-f', data.find_links, 'wheelbroken==0.1',
315+
expect_error=True,
316+
)
317+
wheelnames_path = script.base_path / 'scratch' / 'wheelnames'
318+
with open(wheelnames_path) as f:
319+
wheelnames = f.read().splitlines()
320+
assert wheelnames == []

tests/unit/test_wheel.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pip._vendor.packaging.requirements import Requirement
1010

1111
from pip._internal import pep425tags, wheel
12+
from pip._internal.commands.wheel import WheelCommand
1213
from pip._internal.exceptions import InvalidWheelFilename, UnsupportedWheel
1314
from pip._internal.models.link import Link
1415
from pip._internal.req.req_install import InstallRequirement
@@ -848,3 +849,30 @@ def test_rehash(self, tmpdir):
848849
h, length = wheel.rehash(self.test_file)
849850
assert length == str(self.test_file_len)
850851
assert h == self.test_file_hash_encoded
852+
853+
854+
class TestWheelCommand(object):
855+
856+
def test_save_wheelnames(self, tmpdir):
857+
wheel_filenames = ['Flask-1.1.dev0-py2.py3-none-any.whl']
858+
links_filenames = [
859+
'flask',
860+
'Werkzeug-0.15.4-py2.py3-none-any.whl',
861+
'Jinja2-2.10.1-py2.py3-none-any.whl',
862+
'itsdangerous-1.1.0-py2.py3-none-any.whl',
863+
'Click-7.0-py2.py3-none-any.whl'
864+
]
865+
866+
expected = wheel_filenames + links_filenames[1:]
867+
expected = [filename + '\n' for filename in expected]
868+
temp_file = tmpdir.joinpath('wheelfiles')
869+
870+
WheelCommand('name', 'summary').save_wheelnames(
871+
links_filenames,
872+
temp_file,
873+
wheel_filenames
874+
)
875+
876+
with open(temp_file, 'r') as f:
877+
test_content = f.readlines()
878+
assert test_content == expected

0 commit comments

Comments
 (0)