From b866c291fd1a2f3d42e3c59a5260b955bfd4844f Mon Sep 17 00:00:00 2001 From: ajohns Date: Tue, 16 Jul 2019 11:13:11 +1000 Subject: [PATCH] -install docs updated and copied into wiki -warning msg on cli tools added for non-pip installation -simplified setup.py --- INSTALL.md | 35 +++++++-------- install.py | 21 +++------ src/rez/cli/_entry_points.py | 54 ++++++++++++++++++++--- wiki/pages/Getting-Started.md | 22 +++------- wiki/pages/Installation.md | 82 +++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 57 deletions(-) create mode 100644 wiki/pages/Installation.md diff --git a/INSTALL.md b/INSTALL.md index 0206b74c6..00bd4ac27 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,9 +1,6 @@ -# Installation +## Installation Script -See https://github.com/nerdvegas/rez/wiki/Getting-Started#installation - - -First, install Rez. Download the source, and, from the source directory, run: +To install rez, download the source. Then from the root directory, run: ``` ]$ python ./install.py @@ -22,12 +19,12 @@ You may also want to source the completion script (for bash): source /opt/rez/completion/complete.sh ``` -Do _not_ move the installation - re-install to a new location if you want to -change the install path. If you want to install rez for multiple operating -systems, perform separate installs for each of those systems. +> [[media/icons/warning.png]] Do _not_ move the installation - re-install to a new +> location if you want to change the install path. If you want to install rez for +> multiple operating systems, perform separate installs for each of those systems. -# Installation Via Pip +## Installation Via Pip It is possible to install rez with pip, like so: @@ -42,8 +39,17 @@ command). The reasons are given in the next section. Pip installation is adequate however, if all you require is the rez API, or you don't require its command line tools to be available within a resolved environment. +Note that running pip-installed rez command line tools will print a warning like so: -# Why Not Pip For Production? +``` +Pip-based rez installation detected. Please be aware that rez command line tools +are not guaranteed to function correctly in this case. See +https://github.com/nerdvegas/rez/wiki/Installation#why-not-pip-for-production +for futher details. +``` + + +## Why Not Pip For Production? Rez is not a normal python package. Although it can successfully be installed using standard mechanisms such as pip, this comes with a number of caveats. @@ -74,12 +80,3 @@ possible to perform these extra steps without using a custom installation script Wheels do not give the opportunity to run post-installation code; neither do they provide functionality for specifying interpreter arguments to be added for any given entry point. - -It is possible to get around these issues to some extent, but doing so would -introduce a second code path parallel to the `install.py` -based installation, -and more caveats are introduced. For example, rez tools could detect when they're -run from a non-production installation, and could remove those parts of `sys.path` -that have come from PYTHONPATH. However, this doesn't take into account other -environment variables (such as PYTHONHOME). Neither does it solve the problem of -other unrelated tools remaining visible within the rez environment (and thus -potentially crashing or behaving abnormally). diff --git a/install.py b/install.py index 789dba5f1..445e0f232 100644 --- a/install.py +++ b/install.py @@ -25,7 +25,7 @@ from build_utils.virtualenv.virtualenv import create_environment, path_locations -def get_venv_executable(dest_dir, name): +def get_py_venv_executable(dest_dir): # get virtualenv's python executable _, _, _, venv_bin_dir = path_locations(dest_dir) @@ -34,7 +34,7 @@ def get_venv_executable(dest_dir, name): "PATHEXT": os.environ.get("PATHEXT", "") } - return venv_bin_dir, which(name, env=env) + return venv_bin_dir, which("python", env=env) def run_command(args, cwd=source_path): @@ -45,7 +45,7 @@ def run_command(args, cwd=source_path): def patch_rez_binaries(dest_dir): - venv_bin_path, py_executable = get_venv_executable(dest_dir, "python") + venv_bin_path, py_executable = get_py_venv_executable(dest_dir) specs = get_specifications() @@ -101,19 +101,10 @@ def copy_completion_scripts(dest_dir): def install_rez_from_source(dest_dir): - _, py_executable = get_venv_executable(dest_dir, "python") - _, pip_executable = get_venv_executable(dest_dir, "pip") + _, py_executable = get_py_venv_executable(dest_dir) - # build wheel - run_command([py_executable, "setup.py", "bdist_wheel"]) - - # find built wheel - names = os.listdir(os.path.join(source_path, "dist")) - names = [x for x in names if os.path.splitext(x)[-1] == ".whl"] - whl = os.path.join(source_path, "dist", names[0]) - - # install wheel - run_command([pip_executable, "install", whl]) + # install via pip + run_command([py_executable, "-m", "pip", "install", "."]) if __name__ == "__main__": diff --git a/src/rez/cli/_entry_points.py b/src/rez/cli/_entry_points.py index e7c4b2f86..de9c2994d 100644 --- a/src/rez/cli/_entry_points.py +++ b/src/rez/cli/_entry_points.py @@ -1,6 +1,9 @@ """ Entry points. """ +import os.path +import sys + ### Utility functions @@ -21,8 +24,6 @@ def get_specifications(): Returns: dict (str, str): The specification string for each script name. """ - import sys - specs = {} for attr, obj in sys.modules[__name__].__dict__.iteritems(): @@ -41,10 +42,24 @@ def decorator(fn): return decorator +def check_production_install(): + path = os.path.dirname(sys.argv[0]) + filepath = os.path.join(path, ".rez_production_install") + + if not os.path.exists(filepath): + sys.stderr.write( + "Pip-based rez installation detected. Please be aware that rez command " + "line tools are not guaranteed to function correctly in this case. See " + "https://github.com/nerdvegas/rez/wiki/Installation#why-not-pip-for-production " + " for futher details.\n" + ) + + ### Entry points @scriptname("rez") def run_rez(): + check_production_install() from rez.cli._main import run return run() @@ -53,6 +68,7 @@ def run_rez(): def run_rezolve(): # alias for osx, where rez is a different tool # https://www.unix.com/man-page/osx/1/REZ/ + check_production_install() from rez.cli._main import run return run() @@ -61,155 +77,181 @@ def run_rezolve(): def run_bez(): # TODO: Deprecate. Use custom build commands instead. # https://github.com/nerdvegas/rez/wiki/Building-Packages#custom-build-commands + check_production_install() from rez.cli._bez import run run() @scriptname("_rez-complete") def run_rez_complete(): + check_production_install() from rez.cli._main import run return run("complete") @scriptname("_rez-fwd") def run_rez_fwd(): + check_production_install() from rez.cli._main import run return run("forward") @scriptname("rez-bind") def run_rez_bind(): + check_production_install() from rez.cli._main import run return run("bind") @scriptname("rez-build") -def run_rez_bind(): +def run_rez_build(): + check_production_install() from rez.cli._main import run - return run("bind") + return run("build") @scriptname("rez-config") -def run_rez_bind(): +def run_rez_config(): + check_production_install() from rez.cli._main import run - return run("bind") + return run("config") @scriptname("rez-context") def run_rez_context(): + check_production_install() from rez.cli._main import run return run("context") @scriptname("rez-cp") def run_rez_cp(): + check_production_install() from rez.cli._main import run return run("cp") @scriptname("rez-depends") def run_rez_depends(): + check_production_install() from rez.cli._main import run return run("depends") @scriptname("rez-diff") def run_rez_diff(): + check_production_install() from rez.cli._main import run return run("diff") @scriptname("rez-env") def run_rez_env(): + check_production_install() from rez.cli._main import run return run("env") @scriptname("rez-gui") def run_rez_gui(): + check_production_install() from rez.cli._main import run return run("gui") @scriptname("rez-help") def run_rez_help(): + check_production_install() from rez.cli._main import run return run("help") @scriptname("rez-interpret") def run_rez_interpret(): + check_production_install() from rez.cli._main import run return run("interpret") @scriptname("rez-memcache") def run_rez_memcache(): + check_production_install() from rez.cli._main import run return run("memcache") @scriptname("rez-pip") def run_rez_pip(): + check_production_install() from rez.cli._main import run return run("pip") @scriptname("rez-plugins") def run_rez_plugins(): + check_production_install() from rez.cli._main import run return run("plugins") @scriptname("rez-python") def run_rez_python(): + check_production_install() from rez.cli._main import run return run("python") @scriptname("rez-release") def run_rez_release(): + check_production_install() from rez.cli._main import run return run("release") @scriptname("rez-search") def run_rez_search(): + check_production_install() from rez.cli._main import run return run("search") @scriptname("rez-selftest") def run_rez_selftest(): + check_production_install() from rez.cli._main import run return run("selftest") @scriptname("rez-status") def run_rez_status(): + check_production_install() from rez.cli._main import run return run("status") @scriptname("rez-suite") def run_rez_suite(): + check_production_install() from rez.cli._main import run return run("suite") @scriptname("rez-test") def run_rez_test(): + check_production_install() from rez.cli._main import run return run("test") @scriptname("rez-view") def run_rez_view(): + check_production_install() from rez.cli._main import run return run("view") @scriptname("rez-yaml2py") def run_rez_yaml2py(): + check_production_install() from rez.cli._main import run return run("yaml2py") diff --git a/wiki/pages/Getting-Started.md b/wiki/pages/Getting-Started.md index 3e78142ee..8ac4ae7d0 100644 --- a/wiki/pages/Getting-Started.md +++ b/wiki/pages/Getting-Started.md @@ -1,21 +1,9 @@ -## Installation +## Essential Packages -First, install Rez. Download the source, and from the source directory, run -(with *DEST_DIR* replaced with your install location): - - ]$ python ./install.py -v DEST_DIR - -This installs the Rez command line tools. It will print a message at the end -telling you how to use Rez when the installation has completed. Rez is not a -normal Python package and so you do not typically install it with pip or setup.py. -Do *not* move the installation - re-install to a new location if you want to -change the install path. If you want to install rez for multiple operating -systems, perform separate installs for each of those systems. - -Next, you need to create some essential Rez packages. The *rez-bind* tool creates -Rez packages that reference software already installed on your system. Use the -*--quickstart* argument to bind a set of standard packages (note that you may -require administrative privileges for some of them): +After installation, you need to create some essential Rez packages. The *rez-bind* +tool creates Rez packages that reference software already installed on your system. +Use the *--quickstart* argument to bind a set of standard packages (note that you +may require administrative privileges for some of them): ]$ rez-bind --quickstart Binding platform into /home/ajohns/packages... diff --git a/wiki/pages/Installation.md b/wiki/pages/Installation.md new file mode 100644 index 000000000..00bd4ac27 --- /dev/null +++ b/wiki/pages/Installation.md @@ -0,0 +1,82 @@ +## Installation Script + +To install rez, download the source. Then from the root directory, run: + +``` +]$ python ./install.py +``` + +This installs rez to `/opt/rez`. See `install.py -h` for how to install to a +different location. + +Once the installation is complete, a message tells you how to run it: + +``` +SUCCESS! To activate Rez, add the following path to $PATH: +/opt/rez/bin/rez + +You may also want to source the completion script (for bash): +source /opt/rez/completion/complete.sh +``` + +> [[media/icons/warning.png]] Do _not_ move the installation - re-install to a new +> location if you want to change the install path. If you want to install rez for +> multiple operating systems, perform separate installs for each of those systems. + + +## Installation Via Pip + +It is possible to install rez with pip, like so: + +``` +]$ pip install rez +``` + +However, this comes with a caveat - rez command line tools _are not guaranteed +to work correctly_ once inside a rez environment (ie after using the `rez-env` +command). The reasons are given in the next section. + +Pip installation is adequate however, if all you require is the rez API, or you +don't require its command line tools to be available within a resolved environment. + +Note that running pip-installed rez command line tools will print a warning like so: + +``` +Pip-based rez installation detected. Please be aware that rez command line tools +are not guaranteed to function correctly in this case. See +https://github.com/nerdvegas/rez/wiki/Installation#why-not-pip-for-production +for futher details. +``` + + +## Why Not Pip For Production? + +Rez is not a normal python package. Although it can successfully be installed +using standard mechanisms such as pip, this comes with a number of caveats. +Specifically: + +* When within a rez environment (ie after using the `rez-env` command), the rez + command line tools are not guaranteed to function correctly; +* When within a rez environment, other packages' tools (that were also installed + with pip) remain visible, but are not guaranteed to work. + +When you enter a rez environment, the rez packages in the resolve configure +that environment as they see fit. For example, it is not uncommon for a python +package to append to PYTHONPATH. Environment variables such as PYTHONPATH +affect the behaviour of tools, including rez itself, and this can cause it to +crash or behave abnormally. + +When you use the `install.py` script to install rez, some extra steps are taken +to avoid this problem. Specifically: + +* Rez is installed into a virtualenv so that it operates standalone; +* The rez tools are shebanged with `python -E`, in order to protect them from + environment variables that affect python's behaviour; +* The rez tools are stored in their own directory, so that other unrelated tools + are not visible. + +Due to the way standard wheel-based python installations work, it simply is not +possible to perform these extra steps without using a custom installation script. +Wheels do not give the opportunity to run post-installation code; neither do +they provide functionality for specifying interpreter arguments to be added for +any given entry point.