#!/usr/bin/env python import os import sys import argparse import subprocess from importlib import import_module CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) ZULIP_BOTS_DIR = os.path.join(CURRENT_DIR, '..', 'zulip_bots') sys.path.append(ZULIP_BOTS_DIR) import generate_manifest yellow = '\033[93m' green = '\033[92m' end_format = '\033[0m' bold = '\033[1m' def main(): usage = """./tools/provision Creates a Python virtualenv. Its Python version is equal to the Python version this command is executed with.""" parser = argparse.ArgumentParser(usage=usage) parser.add_argument('--python-interpreter', '-p', metavar='PATH_TO_PYTHON_INTERPRETER', default=os.path.abspath(sys.executable), help='Path to the Python interpreter to use when provisioning.') options = parser.parse_args() base_dir = os.path.abspath(os.path.join(__file__, '..', '..')) py_version_output = subprocess.check_output([options.python_interpreter, '--version'], stderr=subprocess.STDOUT, universal_newlines=True) # The output has the format "Python 1.2.3" py_version_list = py_version_output.split()[1].split('.') py_version = tuple(int(num) for num in py_version_list) venv_name = 'zulip-api-py{}-venv'.format(py_version[0]) venv_dir = os.path.join(base_dir, venv_name) if not os.path.isdir(venv_dir): try: return_code = subprocess.call(['virtualenv', '-p', options.python_interpreter, venv_dir]) except OSError: if subprocess.call(['which', 'virtualenv']): print("{red}Please install the virtualenv package and try again.{end_format}" .format(red='\033[91m', end_format='\033[0m')) sys.exit(1) raise else: if return_code: raise OSError("The command `virtualenv -p {} {}` failed. Virtualenv not created!" .format(options.python_interpreter, venv_dir)) print("New virtualenv created.") else: print("Virtualenv already exists.") if os.path.isdir(os.path.join(venv_dir, 'Scripts')): # POSIX compatibility layer and Linux environment emulation for Windows # Virtual uses /Scripts instead of /bin on Windows. # Read https://virtualenv.pypa.io/en/stable/userguide/ venv_exec_dir = 'Scripts' else: venv_exec_dir = 'bin' # In order to install all required packages for the venv, we need to activate it. Since # the activation script sets environmental variables, it needs to be executed inline with # `import_module`. activate_module_dir = os.path.abspath(os.path.join(venv_dir, venv_exec_dir)) sys.path.append(activate_module_dir) import_module('activate_this') # In order to install all required packages for the venv, `pip` needs to be executed by # the venv's Python interpreter. `--prefix venv_dir` ensures that all modules are installed # in the right place. def install_dependencies(requirements_filename): pip_path = os.path.join(venv_dir, venv_exec_dir, 'pip') # We first install a modern version of pip that supports --prefix subprocess.call([pip_path, 'install', 'pip>=9.0']) if subprocess.call([pip_path, 'install', '--prefix', venv_dir, '-r', os.path.join(base_dir, requirements_filename)]): raise OSError("The command `pip install -r {}` failed. Dependencies not installed!" .format(os.path.join(base_dir, requirements_filename))) install_dependencies('requirements.txt') if py_version > (3, 1): install_dependencies('py3_requirements.txt') else: print(yellow + "Your Python version does not support mypy. `tools/run-mypy` will fail." + end_format) print(green + 'Success!' + end_format) activate_command = os.path.join(base_dir, venv_dir, venv_exec_dir, 'activate') print('\nNow, run this!:') print(bold + 'source ' + activate_command + end_format) if __name__ == '__main__': main()