1
0
forked from VimPlug/jedi

Do binary comparisons to get virtualenvs working and not just venvs

This commit is contained in:
Dave Halter
2018-04-13 21:26:08 +02:00
parent ed80ed9437
commit 8af4fc5728
+42 -8
View File
@@ -1,6 +1,8 @@
import os import os
import re import re
import sys import sys
import hashlib
import filecmp
from subprocess import PIPE from subprocess import PIPE
from collections import namedtuple from collections import namedtuple
# When dropping Python 2.7 support we should consider switching to # When dropping Python 2.7 support we should consider switching to
@@ -30,6 +32,14 @@ class _BaseEnvironment(object):
version_string = '%s.%s' % (self.version_info.major, self.version_info.minor) version_string = '%s.%s' % (self.version_info.major, self.version_info.minor)
return parso.load_grammar(version=version_string) return parso.load_grammar(version=version_string)
@property
def _sha256(self):
try:
return self._hash
except AttributeError:
self._hash = _calculate_sha256_for_file(self.executable)
return self._hash
class _Environment(_BaseEnvironment): class _Environment(_BaseEnvironment):
""" """
@@ -123,6 +133,14 @@ def _get_virtual_env_from_var():
pass pass
def _calculate_sha256_for_file(path):
sha256 = hashlib.sha256()
with open(path, 'rb') as f:
for block in iter(lambda: f.read(filecmp.BUFSIZE), b''):
sha256.update(block)
return sha256.hexdigest()
def get_default_environment(): def get_default_environment():
""" """
Tries to return an active Virtualenv. If there is no VIRTUAL_ENV variable Tries to return an active Virtualenv. If there is no VIRTUAL_ENV variable
@@ -302,15 +320,31 @@ def _is_safe(executable_path):
# Resolve sym links. A venv typically is a symlink to a known Python # Resolve sym links. A venv typically is a symlink to a known Python
# binary. Only virtualenvs copy symlinks around. # binary. Only virtualenvs copy symlinks around.
real_path = os.path.realpath(executable_path) real_path = os.path.realpath(executable_path)
if os.name == 'nt':
# Just check the list of known Python versions. If it's not in there,
# it's likely an attacker or some Python that was not properly
# installed in the system.
for environment in find_python_environments():
if environment.executable == real_path:
return True
return False
if _is_unix_safe_simple(real_path):
return True
# Just check the list of known Python versions. If it's not in there,
# it's likely an attacker or some Python that was not properly
# installed in the system.
for environment in find_python_environments():
if environment.executable == real_path:
return True
else:
# If the versions don't match, just compare the binary files. If we
# don't do that, only venvs will be working and not virtualenvs.
# venvs are symlinks while virtualenvs are actual copies of the
# Python files.
# This still means that if the system Python is updated and the
# virtualenv's Python is not (which is probably never going to get
# upgraded), it will not work with Jedi. IMO that's fine, because
# people should just be using venv. ~ dave
if environment._sha256 == _calculate_sha256_for_file(real_path):
return True
return False
def _is_unix_safe_simple(real_path):
if _is_unix_admin(): if _is_unix_admin():
# In case we are root, just be conservative and # In case we are root, just be conservative and
# only execute known paths. # only execute known paths.