diff --git a/news/2417.bugfix b/news/2417.bugfix new file mode 100644 index 0000000000..bb76c19078 --- /dev/null +++ b/news/2417.bugfix @@ -0,0 +1 @@ +Fixed a logic error which caused ``--deploy --system`` to overwrite editable vcs packages in the pipfile before installing, which caused any installation to fail by default. diff --git a/pipenv/__version__.py b/pipenv/__version__.py index 5692134de0..afc0a7217a 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = '2018.6.25' +__version__ = '2018.6.26.dev0' diff --git a/pipenv/core.py b/pipenv/core.py index 6730038ea5..6fe230c8a1 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -617,7 +617,7 @@ def ensure_project( # Automatically use an activated virtualenv. if PIPENV_USE_SYSTEM: system = True - if not project.pipfile_exists: + if not project.pipfile_exists and not deploy: project.touch_pipfile() # Skip virtualenv creation when --system was used. if not system: @@ -1268,7 +1268,8 @@ def do_init( cleanup_virtualenv(bare=False) sys.exit(1) # Ensure the Pipfile exists. - ensure_pipfile(system=system) + if not deploy: + ensure_pipfile(system=system) if not requirements_dir: cleanup_reqdir = True requirements_dir = TemporaryDirectory( @@ -1915,7 +1916,8 @@ def do_install( package_name = False # Install editable local packages before locking - this gives us access to dist-info if project.pipfile_exists and ( - not project.lockfile_exists or not project.virtualenv_exists + # double negatives are for english readability, leave them alone. + (not project.lockfile_exists and not deploy) or (not project.virtualenv_exists and not system) ): section = project.editable_packages if not dev else project.editable_dev_packages for package in section.keys(): @@ -2569,6 +2571,8 @@ def do_sync( unused=False, sequential=False, pypi_mirror=None, + system=False, + deploy=False, ): # The lock file needs to exist because sync won't write to it. if not project.lockfile_exists: @@ -2581,8 +2585,8 @@ def do_sync( ) sys.exit(1) - # Ensure that virtualenv is available. - ensure_project(three=three, python=python, validate=False) + # Ensure that virtualenv is available if not system. + ensure_project(three=three, python=python, validate=False, deploy=deploy) # Install everything. requirements_dir = TemporaryDirectory( @@ -2595,6 +2599,8 @@ def do_sync( requirements_dir=requirements_dir, ignore_pipfile=True, # Don't check if Pipfile and lock match. pypi_mirror=pypi_mirror, + deploy=deploy, + system=system, ) requirements_dir.cleanup() click.echo(crayons.green('All dependencies are now up-to-date!')) diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index 3fee3d89fc..4a960d8f3f 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -19,7 +19,6 @@ PyPI, InstallRequirement, SafeFileCache, - InstallationError, ) from pipenv.patched.notpip._vendor.packaging.requirements import InvalidRequirement, Requirement @@ -27,6 +26,7 @@ from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier from pipenv.patched.notpip._vendor.packaging.markers import Marker, Op, Value, Variable from pipenv.patched.notpip._vendor.pyparsing import ParseException +from pipenv.patched.notpip._internal.exceptions import InstallationError from ..cache import CACHE_DIR from pipenv.environments import PIPENV_CACHE_DIR @@ -278,13 +278,16 @@ def get_legacy_dependencies(self, ireq): if ireq.editable: try: dist = ireq.get_dist() + except InstallationError: + ireq.run_egg_info() + dist = ireq.get_dist() + except (TypeError, ValueError, AttributeError): + pass + else: if dist.has_metadata('requires.txt'): setup_requires = self.finder.get_extras_links( dist.get_metadata_lines('requires.txt') ) - except (TypeError, ValueError, AttributeError): - pass - try: # Pip < 9 and below reqset = RequirementSet( diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 088aa06c2d..522c13d82e 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -19,7 +19,7 @@ index 4e6174c..75f9b49 100644 # NOTE # We used to store the cache dir under ~/.pip-tools, which is not the diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py -index 1c4b943..07cd667 100644 +index 1c4b943..c4e5b0e 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -4,6 +4,7 @@ from __future__ import (absolute_import, division, print_function, @@ -38,7 +38,6 @@ index 1c4b943..07cd667 100644 + PyPI, + InstallRequirement, + SafeFileCache, -+ InstallationError, ) +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement @@ -46,6 +45,7 @@ index 1c4b943..07cd667 100644 +from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier +from pip._vendor.packaging.markers import Marker, Op, Value, Variable +from pip._vendor.pyparsing import ParseException ++from pip._internal.exceptions import InstallationError + from ..cache import CACHE_DIR +from pipenv.environments import PIPENV_CACHE_DIR @@ -223,10 +223,11 @@ index 1c4b943..07cd667 100644 """ Given a pinned or an editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). -@@ -155,6 +270,20 @@ class PyPIRepository(BaseRepository): +@@ -155,7 +270,24 @@ class PyPIRepository(BaseRepository): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) +- + # Collect setup_requires info from local eggs. + # Do this after we call the preparer on these reqs to make sure their + # egg info has been created @@ -235,16 +236,20 @@ index 1c4b943..07cd667 100644 + if ireq.editable: + try: + dist = ireq.get_dist() ++ except InstallationError: ++ ireq.run_egg_info() ++ dist = ireq.get_dist() ++ except (TypeError, ValueError, AttributeError): ++ pass ++ else: + if dist.has_metadata('requires.txt'): + setup_requires = self.finder.get_extras_links( + dist.get_metadata_lines('requires.txt') + ) -+ except (TypeError, ValueError, AttributeError): -+ pass - try: # Pip < 9 and below -@@ -164,11 +293,14 @@ class PyPIRepository(BaseRepository): + reqset = RequirementSet( +@@ -164,11 +296,14 @@ class PyPIRepository(BaseRepository): download_dir=download_dir, wheel_download_dir=self._wheel_download_dir, session=self.session, @@ -261,7 +266,7 @@ index 1c4b943..07cd667 100644 ) except TypeError: # Pip >= 10 (new resolver!) -@@ -188,17 +320,97 @@ class PyPIRepository(BaseRepository): +@@ -188,17 +323,97 @@ class PyPIRepository(BaseRepository): finder=self.finder, session=self.session, upgrade_strategy="to-satisfy-only", @@ -362,7 +367,7 @@ index 1c4b943..07cd667 100644 return set(self._dependencies_cache[ireq]) def get_hashes(self, ireq): -@@ -217,24 +429,22 @@ class PyPIRepository(BaseRepository): +@@ -217,24 +432,22 @@ class PyPIRepository(BaseRepository): # We need to get all of the candidates that match our current version # pin, these will represent all of the files that could possibly # satisfy this constraint.