Source code for rez.package_bind

# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the Rez Project


from __future__ import print_function

from rez.exceptions import RezBindError, _NeverError
from rez import module_root_path
from rez.util import get_close_pkgs
from rez.utils.formatting import columnise
from rez.utils.logging_ import print_error
from rez.config import config
import argparse
import os.path
import os


[docs]def get_bind_modules(verbose=False): """Get available bind modules. Returns: dict: Map of (name, filepath) listing all bind modules. """ builtin_path = os.path.join(module_root_path, "bind") searchpaths = config.bind_module_path + [builtin_path] bindnames = {} for path in searchpaths: if verbose: print("searching %s..." % path) if not os.path.isdir(path): continue for filename in os.listdir(path): fpath = os.path.join(path, filename) fname, ext = os.path.splitext(filename) if os.path.isfile(fpath) and ext == ".py" \ and not fname.startswith('_'): bindnames[fname] = fpath return bindnames
[docs]def find_bind_module(name, verbose=False): """Find the bind module matching the given name. Args: name (str): Name of package to find bind module for. verbose (bool): If True, print extra output. Returns: str: Filepath to bind module .py file, or None if not found. """ bindnames = get_bind_modules(verbose=verbose) bindfile = bindnames.get(name) if bindfile: return bindfile if not verbose: return None # suggest close matches fuzzy_matches = get_close_pkgs(name, bindnames.keys()) if fuzzy_matches: rows = [(x[0], bindnames[x[0]]) for x in fuzzy_matches] print("'%s' not found. Close matches:" % name) print('\n'.join(columnise(rows))) else: print("No matches.") return None
[docs]def bind_package(name, path=None, version_range=None, no_deps=False, bind_args=None, quiet=False): """Bind software available on the current system, as a rez package. Note: `bind_args` is provided when software is bound via the 'rez-bind' command line tool. Bind modules can define their own command line options, and they will be present in `bind_args` if applicable. Args: name (str): Package name. path (str): Package path to install into; local packages path if None. version_range (`VersionRange`): If provided, only bind the software if it falls within this version range. no_deps (bool): If True, don't bind dependencies. bind_args (list of str): Command line options. quiet (bool): If True, suppress superfluous output. Returns: List of `Variant`: The variant(s) that were installed as a result of binding this package. """ pending = set([name]) installed_variants = [] installed_package_names = set() # bind package and possibly dependencies while pending: pending_ = pending pending = set() exc_type = _NeverError for name_ in pending_: # turn error on binding of dependencies into a warning - we don't # want to skip binding some dependencies because others failed try: variants_ = _bind_package(name_, path=path, version_range=version_range, bind_args=bind_args, quiet=quiet) except exc_type as e: print_error("Could not bind '%s': %s: %s" % (name_, e.__class__.__name__, str(e))) continue installed_variants.extend(variants_) for variant in variants_: installed_package_names.add(variant.name) # add dependencies if not no_deps: for variant in variants_: for requirement in variant.requires: if not requirement.conflict: pending.add(requirement.name) # non-primary packages are treated a little differently version_range = None bind_args = None exc_type = RezBindError if installed_variants and not quiet: print("The following packages were installed:") print() _print_package_list(installed_variants) return installed_variants
def _bind_package(name, path=None, version_range=None, bind_args=None, quiet=False): bindfile = find_bind_module(name, verbose=(not quiet)) if not bindfile: raise RezBindError("Bind module not found for '%s'" % name) # load the bind module namespace = {} with open(bindfile) as stream: exec(compile(stream.read(), stream.name, 'exec'), namespace) # parse bind module params bind_parser = argparse.ArgumentParser(prog="rez bind %s" % name, description="%s bind module" % name) parserfunc = namespace.get("setup_parser") if parserfunc: parserfunc(bind_parser) bind_opts = bind_parser.parse_args(bind_args or []) # make the package install_path = path or config.local_packages_path if not quiet: print("creating package '%s' in %s..." % (name, install_path)) bindfunc = namespace.get("bind") if not bindfunc: raise RezBindError("'bind' function missing in %s" % bindfile) variants = bindfunc(path=install_path, version_range=version_range, opts=bind_opts, parser=bind_parser) return variants def _print_package_list(variants): packages = set([x.parent for x in variants]) packages = sorted(packages, key=lambda x: x.name) rows = [["PACKAGE", "URI"], ["-------", "---"]] rows += [(x.name, x.uri) for x in packages] print('\n'.join(columnise(rows)))