예제 #1
0
def bake_from_request(request, directory, force=False):
    """Generate symlinks for a user's given Rez package request.

    Args:
        request (list[str]):
            The Rez packages to make into a Rez resolve.
        directory (str):
            The absolute path to a directory on-disk to place the
            symlinks under. This path can later be fed directly into
            REZ_PACKAGES_PATH to reproduce the environment.
        force (bool, optional):
            If True, delete any symlinks that may already exist.
            If False and symlinks exist, normal exceptions will be raised.
            Default is False.

    Raises:
        ValueError: If `request` contains 1+ package that does not exist.

    """
    try:
        context = resolved_context.ResolvedContext(request)
    except exceptions.PackageFamilyNotFoundError:
        _LOGGER.exception('Request "%s" was not found.', request)

        raise ValueError(
            'Request "{request}" was not found.'.format(request=request))

    paths = pather.get_paths_from_environment(context.get_environ().items())
    make_symlinks(paths, directory, force=force)
    def test_installed_package_no_variants(self):
        """Create a Rez package with no variants and get the folders affecting PYTHONPATH."""
        dependencies = self._make_test_dependencies()
        package, root = self._make_fake_rez_install_package(
            "some_fake_package",
            "1.0.0",
            textwrap.dedent("""\
                name = "some_fake_package"
                version = "1.0.0"

                def commands():
                    import os

                    env.PYTHONPATH.append(os.path.join("{root}", "python"))
                """),
        )

        context = resolved_context.ResolvedContext(
            ["{package.name}==1.0.0".format(package=package)],
            package_paths=[inspection.get_packages_path_from_package(package)]
            + dependencies + config.packages_path,  # pylint: disable=no-member
        )

        python_files = inspection.get_package_python_paths(
            package,
            context.get_environ().get("PYTHONPATH", "").split(os.pathsep))

        self.assertEqual(
            {os.path.join(root, "some_fake_package", "1.0.0", "python")},
            python_files)
예제 #3
0
def python_config_jam():
    # Lookup all installed python packages
    from rez import packages, resolved_context

    versions = list()

    info_cmd = ("python %s get-python-info" % sys.argv[0])

    for python_pkg in packages.iter_packages("python"):
        full_ver = str(python_pkg.version)
        python_ver = ".".join(full_ver.split(".")[:2])  # exclude patch ver
        versions.append(python_ver)

    versions.sort()
    # Only use python-27 for now (for USD)
    #   because cmake files only link to the version which built latest.
    versions = ["2.7"]

    for python_ver in versions:
        python_name = "python-%s" % python_ver
        rc = resolved_context.ResolvedContext([python_name], caching=False)
        popen = rc.execute_shell(command=info_cmd)
        popen.wait()

    return versions
예제 #4
0
def install(package, root, build_path, version=''):
    '''Install a given package into `build_path`.

    Args:
        root (str):
            The absolute path to where all installed packages live.
        build_path (str):
            The absolute path to install the package to.
        version (str, optional):
            The specific version to get the path of. If no version is given,
            the latest version is used, instead. Default: "".

    '''
    package = package.split('-')[0]

    LOGGER.debug('Installing "%s".', package)

    try:
        # Request the specific package-version
        resolved_context.ResolvedContext(['{}-{}'.format(package, version)])
    except PACKAGE_EXCEPTIONS:
        build_package_recursively(root,
                                  package,
                                  version=version,
                                  build_path=build_path)
예제 #5
0
def build_package_recursively(root, package, version='', build_path=''):
    '''Build a package by building its required packages recursively.

    Basically the logic goes like this:
        - Evaluate if a package has been built. If it has been built, do nothing.
        - If a package has no requirements, build it.
        - If a package has requirements and that requirement isn't installed,
          then evaluate and build it, too.
        - Repeat until all packages are built.

    Raises:
        RuntimeError:
            If a package was build incorrectly or
            if an attempt to build a package failed.

    '''
    def build_definition(definition, build_path):
        try:
            multipurpose_helper.build(
                os.path.dirname(definition.__file__),
                install_path=build_path,
            )
        except Exception:
            # TODO : Consider deleting the contents of
            #        `os.path.dirname(definition.__file__)`
            #        before erroring out, here
            #
            message = 'Definition "%s" failed to build.'
            LOGGER.exception(message, definition.__file__)
            raise RuntimeError(message % definition.__file__)

    LOGGER.debug('Building package "%s".', package)

    definition = get_package_definition(root, package, version)

    if not definition:
        raise RuntimeError('No definition file could be loaded.')

    pkg = make_package(definition, build_path)
    requirements = pkg.get_package().requires

    for requirement in requirements:
        try:
            resolved_context.ResolvedContext([requirement])
        except PACKAGE_EXCEPTIONS:
            requirement_package, requirement_version = str(requirement).split(
                '-')

            build_package_recursively(root,
                                      requirement_package,
                                      requirement_version,
                                      build_path=build_path)

    # Now that all of the requirements are installed, install this package
    build_definition(definition, build_path)
    def test_installed_package_with_variants(self):
        """Create a Rez package with variants and get the folders affecting PYTHONPATH."""
        dependencies = self._make_test_dependencies()
        package = self._make_fake_rez_source_package(
            "some_fake_package",
            textwrap.dedent("""\
                name = "some_fake_package"
                version = "1.0.0"
                variants = [["some_dependency-1", "another_one-2.3"], ["another_one-2.3"]]
                build_command = "echo 'foo'"

                def commands():
                    import os

                    env.PYTHONPATH.append(os.path.join("{root}", "python"))
                """),
        )
        install_path = tempfile.mkdtemp(suffix="_install_path")
        self.delete_item_later(install_path)

        build_package = creator.build(
            package,
            install_path,
            packages_path=dependencies + config.packages_path,  # pylint: disable=no-member
            quiet=True,
        )

        context = resolved_context.ResolvedContext(
            [
                "{build_package.name}==1.0.0".format(
                    build_package=build_package)
            ],
            package_paths=[
                inspection.get_packages_path_from_package(build_package)
            ] + dependencies + config.packages_path,  # pylint: disable=no-member
        )

        python_files = inspection.get_package_python_paths(
            build_package,
            context.get_environ().get("PYTHONPATH", "").split(os.pathsep))

        self.assertEqual(
            {
                os.path.join(
                    install_path,
                    "some_fake_package",
                    "1.0.0",
                    "another_one-2.3",
                    "python",
                )
            },
            python_files,
        )
예제 #7
0
    def execute(self, app_path, app_args, version, engine_name, **kwargs):
        """
        The execute functon of the hook will be called to start the required application
        
        :param app_path: (str) The path of the application executable
        :param app_args: (str) Any arguments the application may require
        :param version: (str) version of the application being run if set in the
            "versions" settings of the Launcher instance, otherwise None
        :param engine_name (str) The name of the engine associated with the
            software about to be launched.

        :returns: (dict) The two valid keys are 'command' (str) and 'return_code' (int).
        """
        if engine_name == "tk-photoshopcc":
            cmd =  "start /B \"App\" \"%s\" %s" % (app_path, app_args)
            exit_code = os.system(cmd)
            return {"command": cmd,
                    "return_code": exit_code

                    }


        app_name = ENGINES[engine_name]
        context = self.tank.context_from_path(self.tank.project_path)
        project = context.project
        sg = self.tank.shotgun
        system = sys.platform
        
        adapter = get_adapter(platform.system())
        
        packages = get_rez_packages(sg,app_name,version,system,project)

        try:
            import rez as _
        except ImportError:
            rez_path = adapter.get_rez_module_root()
            if not rez_path:
                raise EnvironmentError('rez is not installed and could not be automatically found. Cannot continue.')

            sys.path.append(rez_path)
        
        from rez import resolved_context
        

        if not packages:
            self.logger.debug('No rez packages were found. The default boot, instead.')
            command = adapter.get_command(app_path, app_args)
            return_code = os.system(command)
            return {'command': command, 'return_code': return_code}
        context = resolved_context.ResolvedContext(packages)
        return adapter.execute(context, app_args,app_name)
예제 #8
0
    def _get_package_root(package, package_paths):
        root = os.getenv(inspection.get_root_key(package.name), "")

        if root:
            return root

        context = resolved_context.ResolvedContext(
            ["{package.name}=={package.version}".format(package=package)],
            package_paths=package_paths,
        )

        environment = context.get_environ()

        return environment[inspection.get_root_key(package.name)]
    def _make_test_case(self, name, text, extra_paths=None):
        """Create a Rez package that has some Python files inside of it.

        This method exists to make unittesting a bit easier to understand.

        Note:
            This method creates Python files whether `text` actually
            appends to PYTHONPATH or not. They just get ignored by
            unittests, in that case.

        Args:
            name (str):
                The name of the Rez package family to make.
            text (str):
                The source code used for the package.py file.
            extra_paths (list[str], optional):
                A list of paths used to search for Rez packages
                during the Rez resolve that this function calls.
                If no paths are given, Rez will default to
                :attr:`rez.config.packages_path` instead. Default is
                None.

        Returns:
            tuple[set[str], str]:
                The found Python files (excluding __init__.py files)
                and the parent folder where the created package.py goes.

        """
        if not extra_paths:
            extra_paths = []

        package = self._make_fake_rez_source_package(name, text)
        root = finder.get_package_root(package)
        python_root = os.path.join(root, "python")
        os.makedirs(python_root)

        open(os.path.join(python_root, "thing.py"), "w").close()
        open(os.path.join(python_root, "another.py"), "w").close()

        context = resolved_context.ResolvedContext(
            ["{package.name}==".format(package=package)],
            package_paths=[inspection.get_packages_path_from_package(package)]
            + extra_paths + config.packages_path,  # pylint: disable=no-member
        )

        paths = inspection.get_package_python_paths(
            package,
            context.get_environ().get("PYTHONPATH", "").split(os.pathsep))

        return paths, root
    def test_one_error_001(self):
        """Check that calling the tool from commmand-line contains only a single error.

        Run ``rez-documentation-check`` from command-line (in a subprocess).

        Raises:
            RuntimeError: If the called command-line tool fails for any reason.

        """
        paths, importer_package = self._setup_packages()
        local_request = "{package.name}=="
        package_paths = list(paths) + config.packages_path  # pylint: disable=no-member

        context = resolved_context.ResolvedContext(
            [
                _THIS_PACKAGE.name,
                local_request.format(package=importer_package)
            ],
            package_paths=package_paths,
        )

        # This section is a bit complex. Basically, if a user was
        # running rez-documentation-check, normally every dependency of
        # a package would either already be released or a part of the
        # user's packages. To mimic this assumption, we need to define
        # REZ_PACKAGES_PATH to include the importer_package's path +
        # foo_bar, which is one of its dependenices.
        #
        command = _make_check_command(importer_package)
        base = "REZ_PACKAGES_PATH={packages_path}".format(
            packages_path=(os.pathsep).join(package_paths))

        process = context.execute_shell(command=base + " " + command,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
        stdout, stderr = process.communicate()

        if stderr:
            raise RuntimeError(stderr)

        expected = textwrap.dedent("""\
            Missing intersphinx links were found.
            Please add the mapping below to your Sphinx conf.py file.

            intersphinx_mapping = {   'foo_bar': ('https://some_path.com', None)}
            """)

        self.assertTrue(expected in stdout.decode("utf-8"))
    def _test_command(command):
        """Run rez-documentation-check in a fake command-line environment.

        Args:
            command (str):
                The rez-documentation-check command that would run on command-line.

        Returns:
            tuple[str, str]: The stdout and stderr that was created by the given `command`.

        """
        context = resolved_context.ResolvedContext(
            [_THIS_PACKAGE.name, "python-2"])
        process = context.execute_shell(command=command,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)

        return process.communicate()
    def execute_action(self, name, params, sg_publish_data):
        """
        Execute a given action. The data sent to this be method will
        represent one of the actions enumerated by the generate_actions method.
        
        :param name: Action name string representing one of the items returned by generate_actions.
        :param params: Params data, as specified by generate_actions.
        :param sg_publish_data: Shotgun data dictionary with all the standard publish fields.
        :returns: No return value expected.
        """
        app = self.parent

        app.log_debug("Execute action called for action %s. "
                      "Parameters: %s. Publish Data: %s" %
                      (name, params, sg_publish_data))

        # resolve path - forward slashes on all platforms in Nuke
        path = self.get_publish_path(sg_publish_data).replace(os.path.sep, "/")

        if name == "read_channel":
            self._select_channel_view(path, sg_publish_data)

        if name == "rv":

            rez_path = self._get_rez_module()
            sys.path.append(rez_path)
            from rez import resolved_context
            packages = ("rv", )
            context = resolved_context.ResolvedContext(packages)
            command = "rv"
            command += ' {path}'.format(path=path)
            context.execute_shell(
                command=command,
                stdin=False,
                block=False,
            )

        else:
            super(NukeAddActions, self).execute_action(name, params,
                                                       sg_publish_data)
예제 #13
0
def _get_context(packages):
    '''Get a Rez environment that satisfies the given packages, if possible.

    Args:
        packages (list[str]):
            All of the packages that must be contained in the context.
            It can include the name-version of the package
            or just the package name. Example: ["nuke-11.2v3"] or ["nuke"].

    Returns:
        `resolved_context.ResolvedContext` or NoneType:
            The found package countext, assuming `packages`
            has already been built correctly.

    '''
    from rez import resolved_context
    from rezzurect import manager

    try:
        return resolved_context.ResolvedContext(packages)
    except manager.PACKAGE_EXCEPTIONS:
        return
    def execute_action(self, name, params, sg_publish_data):
        """
        Execute a given action. The data sent to this be method will
        represent one of the actions enumerated by the generate_actions method.
        
        :param name: Action name string representing one of the items returned by generate_actions.
        :param params: Params data, as specified by generate_actions.
        :param sg_publish_data: Shotgun data dictionary with all the standard publish fields.
        :returns: No return value expected.
        """
        app = self.parent
        app.log_debug("Execute action called for action %s. "
                      "Parameters: %s. Publish Data: %s" %
                      (name, params, sg_publish_data))

        # resolve path
        path = self.get_publish_path(sg_publish_data)

        if name == "open_project":
            self._open_project(path, sg_publish_data)

        if name == "import_look_file":
            self._open_project(path, sg_publish_data)

        if name == "create_node_Alembic_In":
            self._create_node("ABC",
                              path,
                              sg_publish_data,
                              asset_parameter="abcAsset")

        if name == "create_node_ImageRead":
            self._create_node("ImageRead",
                              path,
                              sg_publish_data,
                              asset_parameter="file")

        if name == "create_pxrusd_in":

            self._create_node("USD",
                              path,
                              sg_publish_data,
                              asset_parameter="fileName")

        if name == "create_scenegraphXml":
            self._create_node("XML",
                              path,
                              sg_publish_data,
                              asset_parameter="asset")

        if name == "viewer":

            rez_path = self._get_rez_module()
            sys.path.append(rez_path)
            from rez import resolved_context
            packages = ("usd", "PySide")
            context = resolved_context.ResolvedContext(packages)
            command = "usdview"
            command += ' {path}'.format(path=path)
            context.execute_shell(
                command=command,
                stdin=False,
                block=False,
            )

        if name == "copy_path":

            rez_path = self._get_rez_module()
            sys.path.append(rez_path)
            from rez import resolved_context
            packages = ("pyperclip", )
            context = resolved_context.ResolvedContext(packages)
            sys.path.append(context.get_environ()['PYTHONPATH'])
            import pyperclip
            pyperclip.copy(path)
def has_python_package(  # pylint: disable=too-many-branches,too-many-locals
        package,
        paths=None,
        allow_build=True,
        allow_current_context=False):
    """Check if the given Rez package has at least one Python package inside of it.

    Note:
        This function assumes that `package` is a built package.
        Otherwise, it may return incorrect results.

    Important:
        This function assumes that all Python packages set / append to
        the PYTHONPATH environment variable. It uses that environment variable
        to find Python packages.

    Args:
        package (:class:`rez.packages_.Package`):
            The Rez package to check for Python packages.
        paths (list[str], optional):
            The locations on-disk that will be used to any
            Rez-environment-related work. Some plugins need these paths
            for resolving a context, for example. If no paths are given,
            :attr:`rez.config.config.packages_path` is used instead.
            Default is None.
        allow_build (bool, optional):
            If `package` is a source Rez package and no importable
            Python modules could be found and this parameter is True,
            build the package to see if its generated content includes
            a Python module. If False though, this function will simply
            return False without building the Rez source package.
            Default is True.

    Raises:
        ValueError: If `package` is not a Rez package.

    Returns:
        bool: If a Python package is detected.

    """
    from . import creator  # Avoiding a cyclic import

    if not hasattr(package, "name") or not hasattr(package, "version"):
        raise ValueError(
            'Object "{package}" is not a valid Rez package.'.format(
                package=package))

    if not paths:
        paths = config.packages_path  # pylint: disable=no-member

    version = ""
    is_built = is_built_package(package)

    if is_built:
        version = package.version

    if allow_current_context and in_valid_context(package):
        environment = os.environ.get("PYTHONPATH", "").split(os.pathsep)
    else:
        context = resolved_context.ResolvedContext(
            [
                "{package.name}=={version}".format(package=package,
                                                   version=version)
            ],
            package_paths=[get_packages_path_from_package(package)] + paths,
        )

        environment = context.get_environ().get("PYTHONPATH",
                                                "").split(os.pathsep)

    paths = get_package_python_paths(package, environment)

    # All zipped .egg files as valid Python "packages"
    for path in paths:
        if path.endswith(".egg") and os.path.isfile(path):
            return True

    for root_path in paths:
        for _, _, files in os.walk(root_path):
            for file_path in files:
                if file_path == "__init__.py":
                    continue

                if file_path.endswith(".py"):
                    return True

    if is_built or not allow_build:
        return False

    # If the package is a source package and PYTHONPATH is defined but
    # no path was found, it may actually be that the Python files are
    # generated on-build (such as C++ files with Python bindings). To
    # find out, we need to run this function again, but with the built
    # package.
    #
    build_directory = tempfile.mkdtemp(
        suffix="_some_temporary_rez_build_package")
    build_package = creator.build(package, build_directory, quiet=True)

    # Reference: https://stackoverflow.com/questions/3850261/doing-something-before-program-exit
    atexit.register(functools.partial(shutil.rmtree, build_directory))

    return has_python_package(build_package)