From a895218013f6937a3e7361d82f06402cc0063c4e Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 11 Apr 2018 22:46:58 +0800 Subject: [PATCH] Resolve Pipfile location for hash caculation This should prevent the lookup loop most of the time, especially for new virtualenvs created from now on. --- pipenv/project.py | 51 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/pipenv/project.py b/pipenv/project.py index f9177d0a..1529068d 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -11,11 +11,15 @@ import hashlib import contoml import delegator -from pipenv.vendor.first import first import pipfile import pipfile.api import toml +try: + import pathlib +except ImportError: + import pathlib2 as pathlib + from pip9 import ConfigOptionParser from .cmdparse import Script from .utils import ( @@ -43,12 +47,19 @@ from .environments import ( PIPENV_PYTHON, ) + +def _normalized(p): + if p is None: + return None + return normalize_drive(str(pathlib.Path(p).resolve())) + + if PIPENV_PIPFILE: if not os.path.isfile(PIPENV_PIPFILE): raise RuntimeError('Given PIPENV_PIPFILE is not found!') else: - PIPENV_PIPFILE = normalize_drive(os.path.abspath(PIPENV_PIPFILE)) + PIPENV_PIPFILE = _normalized(PIPENV_PIPFILE) # (path, file contents) => TOMLFile # keeps track of pipfiles that we've seen so we do not need to re-parse 'em _pipfile_cache = {} @@ -235,20 +246,32 @@ class Project(object): name = self._sanitize(name) hash = hashlib.sha256(location.encode()).digest()[:6] encoded_hash = base64.urlsafe_b64encode(hash).decode() - return name, encoded_hash - pipfile = self.pipfile_location - clean_name, encoded_hash = get_name(name, pipfile) + return name, encoded_hash[:8] + + clean_name, encoded_hash = get_name(name, self.pipfile_location) venv_name = '{0}-{1}'.format(clean_name, encoded_hash) - # Check for different capitalization of the same project on windows - if os.name == 'nt' and not PIPENV_VENV_IN_PROJECT and not self._get_virtualenv_location(venv_name): - from pipenv.patched.pew.pew import lsenvs - env_name = first([env for env in lsenvs() if env.lower().startswith(name.lower())]) - if env_name: - env_name = env_name[:-9] - pipfile = self.pipfile_location.replace(name, env_name) - clean_name, encoded_hash = get_name(env_name, pipfile) + + # This should work most of the time, for non-WIndows, in-project venv, + # or "proper" path casing (on Windows). + if (os.name != 'nt' or + PIPENV_VENV_IN_PROJECT or + self._get_virtualenv_location(venv_name)): + return clean_name, encoded_hash + + # Check for different capitalization of the same project. + from pipenv.patched.pew.pew import lsenvs + for env in lsenvs(): + env_name = env[:-9] + if not (env[-9] != '-' and + env[-8:].isalpha() and + env_name.lower() != name.lower()): + continue + return get_name(env_name, self.pipfile_location.replace(name, env_name)) + + # Use the default if no matching env exists. return clean_name, encoded_hash + @property def virtualenv_name(self): sanitized, encoded_hash = self._get_virtualenv_hash(self.name) @@ -326,7 +349,7 @@ class Project(object): loc = pipfile.Pipfile.find(max_depth=PIPENV_MAX_DEPTH) except RuntimeError: loc = None - self._pipfile_location = normalize_drive(loc) + self._pipfile_location = _normalized(loc) return self._pipfile_location @property