Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Install as package #579

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/install-as-package-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# JUST AN EXPERIMENT - delete/replace as necessary before merge
name: Experimenting with actions - PR 579
on: [push]

jobs:
linux:
name: Ubuntu - install prod. venv
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['2.7', '3.7']
package-name: ['rez', 'foo']
rez-shell: ['bash', 'tcsh']

steps:
- name: Checkout
uses: actions/checkout@master

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
architecture: x64

- name: Check install.py help
run: |
python install.py --help

- name: Install as rez package into HOME/packages
run: |
INSTALL_LOG=$(mktemp)
if [ "${{ matrix.package-name }}" == "rez" ]
then
INSTALL_FLAGS="-p"
else
INSTALL_FLAGS="-P ${{ matrix.package-name }}"
fi
python install.py ${INSTALL_FLAGS} ${HOME}/packages |& tee ${INSTALL_LOG}
# Setup rez activation scripts
echo "export PATH=${PATH}:$(sed -n '/to .PATH:/ {n;p;q}' ${INSTALL_LOG})" > setup-rez.sh

- name: View rez rez package
run: |
source setup-rez.sh
find ${HOME}/packages -maxdepth 5
rez view ${{ matrix.package-name }}

- name: Bind Python and check rez env
run: |
source setup-rez.sh
rez bind python
rez env ${{ matrix.package-name }} -- rez context

- name: rez-selftest
env:
_REZ_SHELL: ${{ matrix.rez-shell }}
run: |
source setup-rez.sh
if [ "$_REZ_SHELL" == "tcsh" ]; then sudo apt-get install tcsh; fi
$(rez env ${{ matrix.package-name }} -- which rez-selftest) -s ${_REZ_SHELL}

# - name: Install in Python Docker Image
161 changes: 127 additions & 34 deletions install.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from rez.cli._entry_points import get_specifications
from rez.backport.shutilwhich import which
from rez.vendor.distlib.scripts import ScriptMaker
from rez.package_maker__ import make_package
from rez.system import system

from build_utils.virtualenv.virtualenv import create_environment, path_locations

Expand Down Expand Up @@ -98,41 +100,13 @@ def copy_completion_scripts(dest_dir):
return None


def install_rez_from_source(dest_dir):
_, py_executable = get_py_venv_executable(dest_dir)

# install via pip
run_command([py_executable, "-m", "pip", "install", "."])


if __name__ == "__main__":
parser = argparse.ArgumentParser("Rez installer")
parser.add_argument(
'-v', '--verbose', action='count', dest='verbose', default=0,
help="Increase verbosity.")
parser.add_argument(
'-s', '--keep-symlinks', action="store_true", default=False,
help="Don't run realpath on the passed DEST_DIR to resolve symlinks; "
"ie, the baked script locations may still contain symlinks")
parser.add_argument(
"DIR", default="/opt/rez", nargs='?',
help="Destination directory. If '{version}' is present, it will be "
"expanded to the rez version. Default: %(default)s")

opts = parser.parse_args()

if " " in os.path.realpath(__file__):
parser.error(
"\nThe absolute path of install.py cannot contain spaces due to setuptools limitation.\n"
"Please move installation files to another location or rename offending folder(s).\n"
)

# determine install path
dest_dir = opts.DIR.format(version=_rez_version)
dest_dir = os.path.expanduser(dest_dir)
if not opts.keep_symlinks:
dest_dir = os.path.realpath(dest_dir)
def install(dest_dir, verbosity=0):
"""Install rez into the given directory.

Args:
dest_dir (str): Full path to the install directory.
verbosity (int): Level of verbosity (typically from args).
"""
print("installing rez to %s..." % dest_dir)

# create the virtualenv
Expand Down Expand Up @@ -174,3 +148,122 @@ def install_rez_from_source(dest_dir):
print(completion_path)

print('')


def install_rez_from_source(dest_dir):
_, py_executable = get_py_venv_executable(dest_dir)

# install via pip
run_command([py_executable, "-m", "pip", "install", "."])


def install_as_package(pkgs_path, pkg_name='rez', verbosity=0):
"""Installs rez as a production rez package (uses virtual environment).

Calls the ``install()`` function internally from the ``make_package``
context.

Args:
pkgs_path (str): Full path to the install directory.
pkg_name (str): Custom name for the rez package to insall rez as.
verbosity (int): Level of verbosity (typically from args).
"""

def make_root(variant, root):
"""Performs install and copies rez python modules.

This mimics the ``rez bind -i rez`` where only the rez Python modules
are exposed to ``PYTHONPATH``.

Args:
variant (rez.packages_.Variant): Install/current package's variant.
root (str): Install folder (see also ``REZ_BUILD_INSTALL_PATH``).
"""
install(root, verbosity=verbosity)

python_folder = os.path.join(root, 'python')
os.mkdir(python_folder)

rez_python = os.path.join(root, 'bin', 'python')
modules_args = [
rez_python, '-E', '-c',
r'import pkg_resources;'
r'rez = pkg_resources.working_set.by_key["rez"];'
r'print(rez.location);' # venv Python site-packages
r'print("\n".join(rez._get_metadata("top_level.txt")))'
]
modules_stdout = str(subprocess.check_output(modules_args))
location = None
for line in filter(None, modules_stdout.splitlines()):
if location is None:
location = line
else:
src = os.path.join(location, line)
dest = os.path.join(python_folder, line)
shutil.copytree(src, dest)

def commands():
"""Setup PYTHONPATH (inspired by src/rez/bind/rez.py)."""
import os
env.PATH.append(os.path.join('{root}', 'bin', 'rez'))
env.PYTHONPATH.append(os.path.join('{root}', 'python'))

if defined('SHELL'):
is_csh = "csh" in str(env.SHELL)
ext = "csh" if is_csh else "sh" # Basic selection logic
source(os.path.join('{root}', 'completion', 'complete.' + ext))

with make_package(pkg_name, pkgs_path, make_root=make_root) as pkg:
pkg.version = _rez_version
pkg.commands = commands
pkg.description = 'Standalone, production-ready Rez installation'
pkg.variants = [[
"platform-{0}".format(system.platform),
"python-{0.major}.{0.minor}".format(sys.version_info)]]


if __name__ == "__main__":
parser = argparse.ArgumentParser(
"Rez installer", description="Install rez in a production ready, "
"standalone Python virtual environment.")
parser.add_argument(
'-v', '--verbose', action='count', dest='verbose', default=0,
help="Increase verbosity.")
parser.add_argument(
'-s', '--keep-symlinks', action="store_true", default=False,
help="Don't run realpath on the passed DIR to resolve symlinks; "
"ie, the baked script locations may still contain symlinks")
package_group = parser.add_mutually_exclusive_group()
package_group.add_argument(
'-p', '--as-rez-package', dest='package',
action="store_const", const="rez",
help="Install using rez package structure as 'rez'. "
"(DIR should be a rez packages directory)")
package_group.add_argument(
'-P', '--as-package', dest='package',
help="Given a package name, install using rez package structure. "
"(DIR should be a rez packages directory)")
parser.add_argument(
"DIR", default="/opt/rez", nargs='?',
help="Destination directory. If '{version}' is present, it will be "
"expanded to the rez version. Default: %(default)s")

opts = parser.parse_args()

if " " in os.path.realpath(__file__):
parser.error(
"\nThe absolute path of install.py cannot contain spaces due to setuptools limitation.\n"
"Please move installation files to another location or rename offending folder(s).\n"
)

# determine install path
dest_dir = opts.DIR.format(version=_rez_version)
dest_dir = os.path.expanduser(dest_dir)
if not opts.keep_symlinks:
dest_dir = os.path.realpath(dest_dir)

if opts.package:
install_as_package(
dest_dir, opts.package, verbosity=opts.verbose)
else:
install(dest_dir, verbosity=opts.verbose)