Skip to content

Commit c86a988

Browse files
committed
Cache wheels built from immutable Git requirements
Cache wheels that are built from Git requirements that contain an immutable revision (i.e. a sha).
1 parent 448303a commit c86a988

File tree

6 files changed

+54
-2
lines changed

6 files changed

+54
-2
lines changed

docs/html/reference/pip_install.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ and use any packages found there. This is disabled via the same
573573
of that is not part of the pip API. As of 7.0, pip makes a subdirectory for
574574
each sdist that wheels are built from and places the resulting wheels inside.
575575

576+
As of version 20.0, pip also caches wheels it built from Git requirements
577+
when such requirements reference an immutable commit hash.
578+
576579
Pip attempts to choose the best wheels from those built in preference to
577580
building a new wheel. Note that this means when a package has both optional
578581
C extensions and builds ``py`` tagged wheels when the C extension can't be built

news/6640.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Cache wheels built from Git requirements that are considered immutable,
2+
because they point to a commit hash.

src/pip/_internal/vcs/git.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pip._vendor.six.moves.urllib import request as urllib_request
1313

1414
from pip._internal.exceptions import BadCommand
15-
from pip._internal.utils.misc import display_path
15+
from pip._internal.utils.misc import display_path, hide_url
1616
from pip._internal.utils.subprocess import make_command
1717
from pip._internal.utils.temp_dir import TempDirectory
1818
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -59,6 +59,13 @@ class Git(VersionControl):
5959
def get_base_rev_args(rev):
6060
return [rev]
6161

62+
def is_immutable_rev_checkout(self, url, dest):
63+
# type: (str, str) -> bool
64+
_, rev_options = self.get_url_rev_options(hide_url(url))
65+
if not rev_options.rev:
66+
return False
67+
return self.is_commit_id_equal(dest, rev_options.rev)
68+
6269
def get_git_version(self):
6370
VERSION_PFX = 'git version '
6471
version = self.run_command(['version'], show_stdout=False)

src/pip/_internal/vcs/versioncontrol.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,20 @@ def get_base_rev_args(rev):
329329
"""
330330
raise NotImplementedError
331331

332+
def is_immutable_rev_checkout(self, url, dest):
333+
# type: (str, str) -> bool
334+
"""
335+
Return true if the commit hash checked out at dest matches
336+
the revision in url.
337+
338+
Always return False, if the VCS does not support immutable commit
339+
hashes.
340+
341+
This method does not check if there are local uncommitted changes
342+
in dest after checkout, as pip currently has no use case for that.
343+
"""
344+
return False
345+
332346
@classmethod
333347
def make_rev_options(cls, rev=None, extra_args=None):
334348
# type: (Optional[str], Optional[CommandArgs]) -> RevOptions

src/pip/_internal/wheel.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from pip._internal.utils.ui import open_spinner
5353
from pip._internal.utils.unpacking import unpack_file
5454
from pip._internal.utils.urls import path_to_url
55+
from pip._internal.vcs import vcs
5556

5657
if MYPY_CHECK_RUNNING:
5758
from typing import (
@@ -838,7 +839,15 @@ def should_cache(
838839
return False
839840

840841
if req.link and req.link.is_vcs:
841-
# VCS checkout. Build wheel just for this run.
842+
# VCS checkout. Build wheel just for this run
843+
# unless it points to an immutable commit hash in which
844+
# case it can be cached.
845+
assert not req.editable
846+
assert req.source_dir
847+
vcs_backend = vcs.get_backend_for_scheme(req.link.scheme)
848+
assert vcs_backend
849+
if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir):
850+
return True
842851
return False
843852

844853
link = req.link

tests/functional/test_vcs_git.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,20 @@ def test_is_commit_id_equal(script):
221221
assert not Git.is_commit_id_equal(version_pkg_path, 'abc123')
222222
# Also check passing a None value.
223223
assert not Git.is_commit_id_equal(version_pkg_path, None)
224+
225+
226+
def test_is_immutable_rev_checkout(script):
227+
version_pkg_path = _create_test_package(script)
228+
commit = script.run(
229+
'git', 'rev-parse', 'HEAD',
230+
cwd=version_pkg_path
231+
).stdout.strip()
232+
assert Git().is_immutable_rev_checkout(
233+
"git+https://g.c/o/r@" + commit, version_pkg_path
234+
)
235+
assert not Git().is_immutable_rev_checkout(
236+
"git+https://g.c/o/r", version_pkg_path
237+
)
238+
assert not Git().is_immutable_rev_checkout(
239+
"git+https://g.c/o/r@master", version_pkg_path
240+
)

0 commit comments

Comments
 (0)