hash_reqs: Include python version when generating hash.

Fixes #12868.
We now also include python version in the format
'major.minor.patchlevel', when generating hash for a
requirement file. This was necessary since packages tend to
break on different versions of python, so it is important to
track the version on which the venv was setup.

WARN: This commit will force all zulip venvs to be recreated.
This commit is contained in:
Aman Agrawal 2020-07-09 22:03:16 +05:30 committed by Tim Abbott
parent 2668829c93
commit 685ec2a098
3 changed files with 40 additions and 5 deletions

View File

@ -2,8 +2,9 @@
import argparse import argparse
import hashlib import hashlib
import os import os
import subprocess
import sys import sys
from typing import Iterable, List, MutableSet from typing import Iterable, List
def expand_reqs_helper(fpath: str) -> List[str]: def expand_reqs_helper(fpath: str) -> List[str]:
@ -27,8 +28,14 @@ def expand_reqs(fpath: str) -> List[str]:
output = expand_reqs_helper(absfpath) output = expand_reqs_helper(absfpath)
return sorted(set(output)) return sorted(set(output))
def python_version() -> str:
"""
Returns the Python version as string 'Python major.minor.patchlevel'
"""
return subprocess.check_output(["/usr/bin/python3", "-VV"], universal_newlines=True)
def hash_deps(deps: Iterable[str]) -> str: def hash_deps(deps: Iterable[str]) -> str:
deps_str = "\n".join(deps) + "\n" deps_str = "\n".join(deps) + "\n" + python_version()
return hashlib.sha1(deps_str.encode('utf-8')).hexdigest() return hashlib.sha1(deps_str.encode('utf-8')).hexdigest()
def main() -> int: def main() -> int:

View File

@ -262,16 +262,19 @@ def do_patch_activate_script(venv_path: str) -> None:
with open(script_path, 'w') as f: with open(script_path, 'w') as f:
f.write("".join(lines)) f.write("".join(lines))
def generate_hash(requirements_file: str) -> str:
path = os.path.join(ZULIP_PATH, 'scripts', 'lib', 'hash_reqs.py')
output = subprocess.check_output([path, requirements_file], universal_newlines=True)
return output.split()[0]
def setup_virtualenv( def setup_virtualenv(
target_venv_path: Optional[str], target_venv_path: Optional[str],
requirements_file: str, requirements_file: str,
patch_activate_script: bool = False, patch_activate_script: bool = False,
) -> str: ) -> str:
sha1sum = generate_hash(requirements_file)
# Check if a cached version already exists # Check if a cached version already exists
path = os.path.join(ZULIP_PATH, 'scripts', 'lib', 'hash_reqs.py')
output = subprocess.check_output([path, requirements_file], universal_newlines=True)
sha1sum = output.split()[0]
if target_venv_path is None: if target_venv_path is None:
cached_venv_path = os.path.join(VENV_CACHE_PATH, sha1sum, 'venv') cached_venv_path = os.path.join(VENV_CACHE_PATH, sha1sum, 'venv')
else: else:

View File

@ -0,0 +1,25 @@
import unittest
import mock
from scripts.lib.hash_reqs import expand_reqs, hash_deps
from tools.setup.setup_venvs import DEV_REQS_FILE
class TestHashCreation(unittest.TestCase):
def test_diff_hash_for_diff_python_version(self) -> None:
with mock.patch('scripts.lib.hash_reqs.python_version', return_value='Python 3.6.9'):
deps = expand_reqs(DEV_REQS_FILE)
hash1 = hash_deps(deps)
with mock.patch('scripts.lib.hash_reqs.python_version', return_value='Python 3.6.9'):
deps = expand_reqs(DEV_REQS_FILE)
hash2 = hash_deps(deps)
with mock.patch('scripts.lib.hash_reqs.python_version', return_value='Python 3.8.2'):
deps = expand_reqs(DEV_REQS_FILE)
hash3 = hash_deps(deps)
assert hash1 == hash2
assert hash1 != hash3