6ac2165bf1
- Replace virtualenv with python 3's native venv feature. The venv used is native to python3.5+, so there's no need for a separate dependency. - Remove redundant activation script. An activation script is required to use the pip and python in the virtual environment, but because we're calling the pip inside the venv, we don't need one. Fixes #625.
121 lines
5.3 KiB
Python
Executable file
121 lines
5.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import subprocess
|
|
import glob
|
|
|
|
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)
|
|
|
|
red = '\033[91m'
|
|
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.')
|
|
parser.add_argument('--force', '-f', action='store_true',
|
|
help='create venv even with outdated Python version.')
|
|
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[0:2])
|
|
venv_name = 'zulip-api-py{}-venv'.format(py_version[0])
|
|
|
|
if py_version <= (3, 1) and (not options.force):
|
|
print(red + "Provision failed: Cannot create venv with outdated Python version ({}).\n"
|
|
"Maybe try `python3 tools/provision`."
|
|
.format(py_version_output.strip()) + end_format)
|
|
sys.exit(1)
|
|
|
|
venv_dir = os.path.join(base_dir, venv_name)
|
|
if not os.path.isdir(venv_dir):
|
|
try:
|
|
return_code = subprocess.call([options.python_interpreter, '-m', 'venv', venv_dir])
|
|
except OSError:
|
|
print("{red}Installation with venv failed. Probable errors are: "
|
|
"You are on Ubuntu and you haven't installed python3-venv,"
|
|
"or you are running an unsupported python version"
|
|
"or python is not installed properly{end_format}"
|
|
.format(red=red, end_format=end_format))
|
|
sys.exit(1)
|
|
raise
|
|
else:
|
|
# subprocess.call returns 0 if a script executed successfully
|
|
if return_code:
|
|
raise OSError("The command `{} -m venv {}` 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
|
|
# venv uses /Scripts instead of /bin on Windows cmd and Power Shell.
|
|
# Read https://docs.python.org/3/library/venv.html
|
|
venv_exec_dir = 'Scripts'
|
|
else:
|
|
venv_exec_dir = 'bin'
|
|
|
|
# On OS X, ensure we use the virtualenv version of the python binary for
|
|
# future subprocesses instead of the version that this script was launched with. See
|
|
# https://stackoverflow.com/questions/26323852/whats-the-meaning-of-pyvenv-launcher-environment-variable
|
|
if '__PYVENV_LAUNCHER__' in os.environ:
|
|
del os.environ['__PYVENV_LAUNCHER__']
|
|
|
|
# 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')
|
|
|
|
# Install all requirements for all bots. get_bot_paths()
|
|
# has requirements that must be satisfied prior to calling
|
|
# it by setup().
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
bots_dir = os.path.join(current_dir, "..", "zulip_bots", "zulip_bots", "bots")
|
|
req_paths = glob.glob(bots_dir + "/*/requirements.txt")
|
|
for req_path in req_paths:
|
|
path_split = req_path.split(os.path.sep)[-5:]
|
|
relative_path = os.path.join(*path_split)
|
|
install_dependencies(relative_path)
|
|
|
|
print(green + 'Success!' + end_format)
|
|
|
|
activate_command = os.path.join(base_dir,
|
|
venv_dir,
|
|
venv_exec_dir,
|
|
'activate')
|
|
# We make the path look like a Unix path, because most Windows users
|
|
# are likely to be running in a bash shell.
|
|
activate_command = activate_command.replace(os.sep, '/')
|
|
print('\nRun the following to enter into the virtualenv:\n')
|
|
print(bold + ' source ' + activate_command + end_format + "\n")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|