Ejemplo n.º 1
0
    def create_build_context(self, variant, build_type, build_path):
        """Create a context to build the variant within."""
        request = variant.get_requires(build_requires=True,
                                       private_build_requires=True)

        requests_str = ' '.join(map(str, request))
        self._print("Resolving build environment: %s", requests_str)
        if build_type == BuildType.local:
            packages_path = self.package.config.packages_path
        else:
            packages_path = self.package.config.nonlocal_packages_path

        context = ResolvedContext(request,
                                  package_paths=packages_path,
                                  building=True)
        if self.verbose:
            context.print_info()

        # save context before possible fail, so user can debug
        rxt_filepath = os.path.join(build_path, "build.rxt")
        context.save(rxt_filepath)

        if context.status != ResolverStatus.solved:
            raise BuildContextResolveError(context)
        return context, rxt_filepath
Ejemplo n.º 2
0
def spawnRezManagedCommandWatcher(pidfile, logfile, args, watcherPackages, env):
    """
    | Uses rez module to start a process with a proper rez env.

    :param pidfile: full path to the comand pid file (usally /var/run/puli/cw<command_id>.pid)
    :param logfile: file object to store process log content
    :param args: arguments passed to the CommandWatcher script
    :param watcherPackages: A list of packages that will be resolved when creating Rez context
    :param env: a dict holding key/value pairs that will be merged into the current env and used in subprocess

    :return: a CommandWatcherProcess object holding command watcher process handle
    """
    try:
        from rez.resources import clear_caches
        from rez.resolved_context import ResolvedContext
        from rez.resolver import ResolverStatus
    except ImportError as e:
        LOGGER.error("Unable to load rez package in a rez managed environment.")
        raise e

    try:
        if watcherPackages is None:
            LOGGER.warning("No package specified for this command, it might not find the runner for this command.")
            watcherPackagesList = []
        elif type(watcherPackages) in [str, unicode]:
            watcherPackagesList = watcherPackages.split()
        else:
            watcherPackagesList = watcherPackages

        clear_caches()
        context = ResolvedContext(watcherPackagesList)
        success = (context.status == ResolverStatus.solved)
        if not success:
            context.print_info(buf=sys.stderr)
            raise

        # normalize environment
        # JSA do not transmit env (eg PYTHONHOME) to command watcher
        # envN = os.environ.copy()
        envN = {}
        for key in env:
            envN[str(key)] = str(env[key])

        proc = context.execute_shell(
            command=args,
            shell='bash',
            stdin=False,
            stdout=logfile,
            stderr=subprocess.STDOUT,
            block=False,
            parent_environ=envN
        )

        LOGGER.info("Starting subprocess, log: %r, args: %r" % (logfile.name, args))
    except Exception as e:
        LOGGER.error("Impossible to start process: %s" % e)
        raise e

    file(pidfile, "w").write(str(proc.pid))
    return CommandWatcherProcess(proc, pidfile, proc.pid)
Ejemplo n.º 3
0
    def test_create_context(self):
        """Test creation of context."""
        r = ResolvedContext([])
        r.print_info()

        r = ResolvedContext(["hello_world"])
        r.print_info()
Ejemplo n.º 4
0
    def test_create_context(self):
        """Test creation of context."""
        r = ResolvedContext([])
        r.print_info()

        r = ResolvedContext(["hello_world"])
        r.print_info()
Ejemplo n.º 5
0
    def create_build_context(self, variant, build_type, build_path):
        """Create a context to build the variant within."""
        request = variant.get_requires(build_requires=True,
                                       private_build_requires=True)

        requests_str = ' '.join(map(str, request))
        self._print("Resolving build environment: %s", requests_str)
        if build_type == BuildType.local:
            packages_path = self.package.config.packages_path
        else:
            packages_path = self.package.config.nonlocal_packages_path

        context = ResolvedContext(request,
                                  package_paths=packages_path,
                                  building=True)
        if self.verbose:
            context.print_info()

        # save context before possible fail, so user can debug
        rxt_filepath = os.path.join(build_path, "build.rxt")
        context.save(rxt_filepath)

        if context.status != ResolverStatus.solved:
            raise BuildContextResolveError(context)
        return context, rxt_filepath
Ejemplo n.º 6
0
    def _get_context(self, requires, quiet=False):

        # if using current env, only return current context if it meets
        # requirements, otherwise return None
        if self.use_current_env:
            current_context = ResolvedContext.get_current()
            if current_context is None:
                return None

            reqs = map(Requirement, requires)
            current_reqs = current_context.get_resolve_as_exact_requests()

            meets_requirements = (
                RequirementList(current_reqs)
                == RequirementList(current_reqs + reqs)
            )

            if meets_requirements:
                return current_context
            else:
                return None

        # create context or use cached context
        key = tuple(requires)
        context = self.contexts.get(key)

        if context is None:
            if self.verbose and not quiet:
                self._print_header(
                    "Resolving test environment: %s\n",
                    ' '.join(map(quote, requires))
                )

            with open(os.devnull, 'w') as f:
                context = ResolvedContext(
                    package_requests=requires,
                    package_paths=self.package_paths,
                    buf=(f if quiet else None),
                    timestamp=self.timestamp,
                    **self.context_kwargs
                )

            self.contexts[key] = context

        if not context.success and not quiet:
            context.print_info(buf=self.stderr)

        return context
Ejemplo n.º 7
0
    def create_build_context(self, variant, build_type, build_path):
        """Create a context to build the variant within."""
        request = variant.get_requires(build_requires=True,
                                       private_build_requires=True)

        req_strs = map(str, request)
        quoted_req_strs = map(quote, req_strs)
        self._print("Resolving build environment: %s",
                    ' '.join(quoted_req_strs))

        if build_type == BuildType.local:
            packages_path = self.package.config.packages_path
        else:
            packages_path = self.package.config.nonlocal_packages_path

        # It is uncommon, but possible, to define the package filters in the
        # developer package. Example scenario: you may want to enable visiblity
        # of *.dev packages if the current package is *.dev also, for example
        # (assuming you have a production-time package filter which filters out
        # *.dev packages by default).
        #
        if self.package.config.is_overridden("package_filter"):
            from rez.package_filter import PackageFilterList

            data = self.package.config.package_filter
            package_filter = PackageFilterList.from_pod(data)
        else:
            package_filter = None

        # create the build context
        context = ResolvedContext(request,
                                  package_paths=packages_path,
                                  package_filter=package_filter,
                                  building=True)
        if self.verbose:
            context.print_info()

        # save context before possible fail, so user can debug
        rxt_filepath = os.path.join(build_path, "build.rxt")
        context.save(rxt_filepath)

        if context.status != ResolverStatus.solved:
            raise BuildContextResolveError(context)
        return context, rxt_filepath
Ejemplo n.º 8
0
    def create_build_context(self, variant, build_type, build_path):
        """Create a context to build the variant within."""
        request = variant.get_requires(build_requires=True,
                                       private_build_requires=True)

        req_strs = map(str, request)
        quoted_req_strs = map(quote, req_strs)
        self._print("Resolving build environment: %s",
                    ' '.join(quoted_req_strs))

        if build_type == BuildType.local:
            packages_path = self.package.config.packages_path
        else:
            packages_path = self.package.config.nonlocal_packages_path

        if self.package.config.is_overridden("package_filter"):
            from rez.package_filter import PackageFilterList

            data = self.package.config.package_filter
            package_filter = PackageFilterList.from_pod(data)
        else:
            package_filter = None

        context = ResolvedContext(request,
                                  package_paths=packages_path,
                                  package_filter=package_filter,
                                  building=True)
        if self.verbose:
            context.print_info()

        # save context before possible fail, so user can debug
        rxt_filepath = os.path.join(build_path, "build.rxt")
        context.save(rxt_filepath)

        if context.status != ResolverStatus.solved:
            raise BuildContextResolveError(context)
        return context, rxt_filepath
Ejemplo n.º 9
0
    def create_build_context(self, variant, build_type, build_path):
        """Create a context to build the variant within."""
        request = variant.get_requires(build_requires=True,
                                       private_build_requires=True)

        req_strs = map(str, request)
        quoted_req_strs = map(quote, req_strs)
        self._print("Resolving build environment: %s", ' '.join(quoted_req_strs))

        if build_type == BuildType.local:
            packages_path = self.package.config.packages_path
        else:
            packages_path = self.package.config.nonlocal_packages_path

        if self.package.config.is_overridden("package_filter"):
            from rez.package_filter import PackageFilterList

            data = self.package.config.package_filter
            package_filter = PackageFilterList.from_pod(data)
        else:
            package_filter = None

        context = ResolvedContext(request,
                                  package_paths=packages_path,
                                  package_filter=package_filter,
                                  building=True)
        if self.verbose:
            context.print_info()

        # save context before possible fail, so user can debug
        rxt_filepath = os.path.join(build_path, "build.rxt")
        context.save(rxt_filepath)

        if context.status != ResolverStatus.solved:
            raise BuildContextResolveError(context)
        return context, rxt_filepath
Ejemplo n.º 10
0
    def run_test(self, test_name):
        """Run a test.

        Runs the test in its correct environment. Note that if tests share the
        same requirements, the contexts will be reused.

        TODO: If the package had variants, the test will be run for each
        variant.

        Returns:
            int: Returncode - zero if all test(s) passed, otherwise the return
                code of the failed test.
        """
        def print_header(txt, *nargs):
            pr = Printer(sys.stdout)
            pr(txt % nargs, heading)

        package = self.get_package()

        if test_name not in self.get_test_names():
            raise PackageTestError("Test '%s' not found in package %s" %
                                   (test_name, package.uri))

        if self.use_current_env:
            return self._run_test_in_current_env(test_name)

        for variant in package.iter_variants():

            # get test info for this variant. If None, that just means that this
            # variant doesn't provide this test. That's ok - 'tests' might be
            # implemented as a late function attribute that provides some tests
            # for some variants and not others
            #
            test_info = self._get_test_info(test_name, variant)
            if not test_info:
                continue

            command = test_info["command"]
            requires = test_info["requires"]

            # expand refs like {root} in commands
            if isinstance(command, basestring):
                command = variant.format(command)
            else:
                command = map(variant.format, command)

            # show progress
            if self.verbose:
                print_header("\nTest: %s\nPackage: %s\n%s\n", test_name,
                             variant.uri, '-' * 80)

            # create test env
            key = tuple(requires)
            context = self.contexts.get(key)

            if context is None:
                if self.verbose:
                    print_header("Resolving test environment: %s\n",
                                 ' '.join(map(quote, requires)))

                context = ResolvedContext(package_requests=requires,
                                          package_paths=self.package_paths,
                                          buf=self.stdout,
                                          timestamp=self.timestamp,
                                          **self.context_kwargs)

                if not context.success:
                    context.print_info(buf=self.stderr)
                    raise PackageTestError(
                        "Cannot run test '%s' of package %s: the environment "
                        "failed to resolve" % (test_name, variant.uri))

                self.contexts[key] = context

            # run the test in the context
            if self.verbose:
                context.print_info(self.stdout)

                if isinstance(command, basestring):
                    cmd_str = command
                else:
                    cmd_str = ' '.join(map(quote, command))

                print_header("\nRunning test command: %s\n" % cmd_str)

            retcode, _, _ = context.execute_shell(command=command,
                                                  stdout=self.stdout,
                                                  stderr=self.stderr,
                                                  block=True)

            if retcode:
                return retcode

            # TODO FIXME we don't iterate over all variants yet, because we
            # can't reliably do that (see class docstring)
            break

        return 0  # success
Ejemplo n.º 11
0
def command(opts, parser, extra_arg_groups=None):
    from rez.resolved_context import ResolvedContext
    from rez.resolver import ResolverStatus
    from rez.package_filter import PackageFilterList, Rule
    from rez.utils.formatting import get_epoch_time_from_str
    from rez.config import config
    import select
    import sys
    import os
    import os.path

    command = opts.command
    if extra_arg_groups:
        if opts.command:
            parser.error(
                "argument --command: not allowed with arguments after '--'")
        command = extra_arg_groups[0] or None

    context = None
    request = opts.PKG
    t = get_epoch_time_from_str(opts.time) if opts.time else None

    if opts.paths is None:
        pkg_paths = (config.nonlocal_packages_path if opts.no_local else None)
    else:
        pkg_paths = opts.paths.split(os.pathsep)
        pkg_paths = [os.path.expanduser(x) for x in pkg_paths if x]

    if opts.input:
        if opts.PKG:
            parser.error(
                "Cannot use --input and provide PKG(s) at the same time")
        context = ResolvedContext.load(opts.input)
        if context.status != ResolverStatus.solved:
            print >> sys.stderr, "cannot rez-env into a failed context"
            sys.exit(1)

    if opts.patch:
        # TODO: patching is lagging behind in options, and needs to be updated
        # anyway.
        if context is None:
            from rez.status import status
            context = status.context
            if context is None:
                print >> sys.stderr, "cannot patch: not in a context"
                sys.exit(1)

        request = context.get_patched_request(request,
                                              strict=opts.strict,
                                              rank=opts.patch_rank)
        context = None

    if context is None:
        # create package filters
        if opts.no_filters:
            package_filter = PackageFilterList()
        else:
            package_filter = PackageFilterList.singleton.copy()

        for rule_str in (opts.exclude or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_exclusion(rule)

        for rule_str in (opts.include or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_inclusion(rule)

        # perform the resolve
        context = ResolvedContext(package_requests=request,
                                  timestamp=t,
                                  package_paths=pkg_paths,
                                  building=opts.build,
                                  package_filter=package_filter,
                                  add_implicit_packages=(not opts.no_implicit),
                                  verbosity=opts.verbose,
                                  max_fails=opts.max_fails,
                                  time_limit=opts.time_limit,
                                  caching=(not opts.no_cache))

    success = (context.status == ResolverStatus.solved)
    if not success:
        context.print_info(buf=sys.stderr)

    if opts.output:
        if opts.output == '-':  # print to stdout
            context.write_to_buffer(sys.stdout)
        else:
            context.save(opts.output)
        sys.exit(0 if success else 1)

    if not success:
        sys.exit(1)

    # generally shells will behave as though the '-s' flag was not present when
    # no stdin is available. So here we replicate this behaviour.
    if opts.stdin and not select.select([sys.stdin], [], [], 0.0)[0]:
        opts.stdin = False

    quiet = opts.quiet or bool(command)
    returncode, _, _ = context.execute_shell(
        shell=opts.shell,
        rcfile=opts.rcfile,
        norc=opts.norc,
        command=command,
        stdin=opts.stdin,
        quiet=quiet,
        start_new_session=opts.new_session,
        detached=opts.detached,
        pre_command=opts.pre_command,
        block=True)

    sys.exit(returncode)
Ejemplo n.º 12
0
def command(opts, parser, extra_arg_groups=None):
    from rez.resolved_context import ResolvedContext
    from rez.resolver import ResolverStatus
    from rez.package_filter import PackageFilterList, Rule
    from rez.utils.formatting import get_epoch_time_from_str
    from rez.config import config
    import select
    import sys
    import os
    import os.path

    command = opts.command
    if extra_arg_groups:
        if opts.command:
            parser.error("argument --command: not allowed with arguments after '--'")
        command = extra_arg_groups[0] or None

    context = None
    request = opts.PKG
    t = get_epoch_time_from_str(opts.time) if opts.time else None

    if opts.paths is None:
        pkg_paths = (config.nonlocal_packages_path
                     if opts.no_local else None)
    else:
        pkg_paths = opts.paths.split(os.pathsep)
        pkg_paths = [os.path.expanduser(x) for x in pkg_paths if x]

    if opts.input:
        if opts.PKG and not opts.patch:
            parser.error("Cannot use --input and provide PKG(s), unless patching.")

        context = ResolvedContext.load(opts.input)

    if opts.patch:
        if context is None:
            from rez.status import status
            context = status.context
            if context is None:
                print >> sys.stderr, "cannot patch: not in a context"
                sys.exit(1)

        # modify the request in terms of the given patch request
        request = context.get_patched_request(request,
                                              strict=opts.strict,
                                              rank=opts.patch_rank)
        context = None

    if context is None:
        # create package filters
        if opts.no_filters:
            package_filter = PackageFilterList()
        else:
            package_filter = PackageFilterList.singleton.copy()

        for rule_str in (opts.exclude or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_exclusion(rule)

        for rule_str in (opts.include or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_inclusion(rule)

        # perform the resolve
        context = ResolvedContext(package_requests=request,
                                  timestamp=t,
                                  package_paths=pkg_paths,
                                  building=opts.build,
                                  package_filter=package_filter,
                                  add_implicit_packages=(not opts.no_implicit),
                                  verbosity=opts.verbose,
                                  max_fails=opts.max_fails,
                                  time_limit=opts.time_limit,
                                  caching=(not opts.no_cache),
                                  suppress_passive=opts.no_passive,
                                  print_stats=opts.stats)

    success = (context.status == ResolverStatus.solved)

    if not success:
        context.print_info(buf=sys.stderr)
        if opts.fail_graph:
            if context.graph:
                from rez.utils.graph_utils import view_graph
                g = context.graph(as_dot=True)
                view_graph(g)
            else:
                print >> sys.stderr, \
                    "the failed resolve context did not generate a graph."

    if opts.output:
        if opts.output == '-':  # print to stdout
            context.write_to_buffer(sys.stdout)
        else:
            context.save(opts.output)
        sys.exit(0 if success else 1)

    if not success:
        sys.exit(1)

    # generally shells will behave as though the '-s' flag was not present when
    # no stdin is available. So here we replicate this behaviour.
    try:
        if opts.stdin and not select.select([sys.stdin], [], [], 0.0)[0]:
            opts.stdin = False
    except select.error:
        pass  # because windows

    quiet = opts.quiet or bool(command)
    returncode, _, _ = context.execute_shell(
        shell=opts.shell,
        rcfile=opts.rcfile,
        norc=opts.norc,
        command=command,
        stdin=opts.stdin,
        quiet=quiet,
        start_new_session=opts.new_session,
        detached=opts.detached,
        pre_command=opts.pre_command,
        block=True)

    sys.exit(returncode)
Ejemplo n.º 13
0
    def execute(self, app_path, app_args, version, **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

        :returns: (dict) The two valid keys are 'command' (str) and 'return_code' (int).
        """

        multi_launchapp = self.parent
        extra = multi_launchapp.get_setting("extra")

        use_rez = False
        if self.check_rez():
            from rez.resolved_context import ResolvedContext
            from rez.config import config

            # Define variables used to bootstrap tank from overwrite on first reference
            # PYTHONPATH is used by tk-maya
            # NUKE_PATH is used by tk-nuke
            # HIERO_PLUGIN_PATH is used by tk-nuke (nukestudio)
            # KATANA_RESOURCES is used by tk-katana
            config.parent_variables = [
                "PYTHONPATH", "HOUDINI_PATH", "NUKE_PATH", "HIERO_PLUGIN_PATH",
                "KATANA_RESOURCES"
            ]

            rez_packages = extra["rez_packages"]
            context = ResolvedContext(rez_packages)

            use_rez = True

        else:
            print('Can not found rez.')

        system = sys.platform
        shell_type = 'bash'
        if system == "linux2":
            # on linux, we just run the executable directly
            cmd = "%s %s &" % (app_path, app_args)
            #cmd = "%s &" % (app_path)

        elif self.parent.get_setting("engine") in ["tk-flame", "tk-flare"]:
            # flame and flare works in a different way from other DCCs
            # on both linux and mac, they run unix-style command line
            # and on the mac the more standardized "open" command cannot
            # be utilized.
            cmd = "%s %s &" % (app_path, app_args)

        elif system == "darwin":
            # on the mac, the executable paths are normally pointing
            # to the application bundle and not to the binary file
            # embedded in the bundle, meaning that we should use the
            # built-in mac open command to execute it
            cmd = "open -n \"%s\"" % (app_path)
            if app_args:
                cmd += " --args \"%s\"" % app_args.replace("\"", "\\\"")

        elif system == "win32":
            # on windows, we run the start command in order to avoid
            # any command shells popping up as part of the application launch.
            cmd = "start /B \"App\" \"%s\" %s" % (app_path, app_args)
            shell_type = 'cmd'

        print('use_rez:{0}'.format(use_rez))
        # Execute App in a Rez context
        if use_rez:
            n_env = os.environ.copy()
            proc = context.execute_shell(command=cmd,
                                         parent_environ=n_env,
                                         shell=shell_type,
                                         stdin=False,
                                         block=False)
            exit_code = proc.wait()
            print('exit_code:{0}'.format(exit_code))
            context.print_info(verbosity=True)

        else:
            # run the command to launch the app
            exit_code = os.system(cmd)

        return {"command": cmd, "return_code": exit_code}
Ejemplo n.º 14
0
    def execute(self, app_path, app_args, version, **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

        :returns: (dict) The two valid keys are 'command' (str) and 'return_code' (int).
        """

        multi_launchapp = self.parent
        extra = multi_launchapp.get_setting("extra")

        use_rez = False
        if self.check_rez():
            rez_packages = extra["rez_packages"]
            from rez.resolved_context import ResolvedContext
            from rez.config import config
            config.parent_variables = ["PYTHONPATH"]
            context = ResolvedContext(rez_packages)

            use_rez = True

        system = sys.platform
        shell_type = 'bash'
        if system == "linux2":
            # on linux, we just run the executable directly
            cmd = "%s %s &" % (app_path, app_args)

        elif self.parent.get_setting("engine") in ["tk-flame", "tk-flare"]:
            # flame and flare works in a different way from other DCCs
            # on both linux and mac, they run unix-style command line
            # and on the mac the more standardized "open" command cannot
            # be utilized.
            cmd = "%s %s &" % (app_path, app_args)

        elif system == "darwin":
            # on the mac, the executable paths are normally pointing
            # to the application bundle and not to the binary file
            # embedded in the bundle, meaning that we should use the
            # built-in mac open command to execute it
            cmd = "open -n \"%s\"" % (app_path)
            if app_args:
                cmd += " --args \"%s\"" % app_args.replace("\"", "\\\"")

        elif system == "win32":
            # on windows, we run the start command in order to avoid
            # any command shells popping up as part of the application launch.
            cmd = "start /B \"App\" \"%s\" %s" % (app_path, app_args)
            shell_type = 'cmd'

        # Execute App in a Rez context
        if use_rez:
            n_env = os.environ.copy()
            proc = context.execute_shell(
                command=cmd,
                parent_environ=n_env,
                shell=shell_type,
                stdin=False,
                block=False
            )
            exit_code = proc.wait()
            context.print_info(verbosity=True)

        else:
            # run the command to launch the app
            exit_code = os.system(cmd)

        return {
            "command": cmd,
            "return_code": exit_code
        }
Ejemplo n.º 15
0
def command(opts, parser, extra_arg_groups=None):
    from rez.resolved_context import ResolvedContext
    from rez.resolver import ResolverStatus
    from rez.package_filter import PackageFilterList, Rule
    from rez.utils.formatting import get_epoch_time_from_str
    from rez.config import config
    import select
    import sys
    import os
    import os.path

    command = opts.command
    if extra_arg_groups:
        if opts.command:
            parser.error("argument --command: not allowed with arguments after '--'")
        command = extra_arg_groups[0] or None

    context = None
    request = opts.PKG
    t = get_epoch_time_from_str(opts.time) if opts.time else None

    if opts.isolated:
        config.inherit_parent_environment = False

    if opts.inherited:
        config.inherit_parent_environment = True

    if opts.paths is None:
        pkg_paths = (config.nonlocal_packages_path
                     if opts.no_local else None)
    else:
        pkg_paths = opts.paths.split(os.pathsep)
        pkg_paths = [os.path.expanduser(x) for x in pkg_paths if x]

    if opts.input:
        if opts.PKG and not opts.patch:
            parser.error("Cannot use --input and provide PKG(s), unless patching.")

        context = ResolvedContext.load(opts.input)

    if opts.patch:
        if context is None:
            from rez.status import status
            context = status.context
            if context is None:
                print("cannot patch: not in a context", file=sys.stderr)
                sys.exit(1)

        # modify the request in terms of the given patch request
        request = context.get_patched_request(request,
                                              strict=opts.strict,
                                              rank=opts.patch_rank)
        context = None

    if opts.self:
        from rez.utils._version import _rez_version
        request += ["bleeding_rez==%s" % _rez_version]
        request += ["python"]  # Required by Rez

    if context is None:
        # create package filters
        if opts.no_filters:
            package_filter = PackageFilterList()
        else:
            package_filter = PackageFilterList.singleton.copy()

        for rule_str in (opts.exclude or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_exclusion(rule)

        for rule_str in (opts.include or []):
            rule = Rule.parse_rule(rule_str)
            package_filter.add_inclusion(rule)

        # perform the resolve
        context = ResolvedContext(package_requests=request,
                                  timestamp=t,
                                  package_paths=pkg_paths,
                                  building=opts.build,
                                  package_filter=package_filter,
                                  add_implicit_packages=(not opts.no_implicit),
                                  verbosity=opts.verbose,
                                  max_fails=opts.max_fails,
                                  time_limit=opts.time_limit,
                                  caching=(not opts.no_cache),
                                  suppress_passive=opts.no_passive,
                                  print_stats=opts.stats)

    success = (context.status == ResolverStatus.solved)

    if not success:
        context.print_info(buf=sys.stderr)
        if opts.fail_graph:
            if context.graph:
                from rez.utils.graph_utils import view_graph
                g = context.graph(as_dot=True)
                view_graph(g)
            else:
                print("the failed resolve context did not generate a graph.", file=sys.stderr)

    if opts.output:
        if opts.output == '-':  # print to stdout
            context.write_to_buffer(sys.stdout)
        else:
            context.save(opts.output)
        sys.exit(0 if success else 1)

    if not success:
        sys.exit(1)

    if opts.env:
        env = {}

        for pair in opts.env:
            key, value = pair.split("=")
            env[key.upper()] = value

        config.additional_environment = env

    # generally shells will behave as though the '-s' flag was not present when
    # no stdin is available. So here we replicate this behaviour.
    try:
        if opts.stdin and not select.select([sys.stdin], [], [], 0.0)[0]:
            opts.stdin = False
    except select.error:
        pass  # because windows

    quiet = opts.quiet or bool(command)
    returncode, _, _ = context.execute_shell(
        shell=opts.shell,
        rcfile=opts.rcfile,
        norc=opts.norc,
        command=command,
        stdin=opts.stdin,
        quiet=quiet,
        start_new_session=opts.new_session,
        detached=opts.detached,
        pre_command=opts.pre_command,
        block=True)

    sys.exit(returncode)
Ejemplo n.º 16
0
    def run_test(self, test_name):
        """Run a test.

        Runs the test in its correct environment. Note that if tests share the
        same requirements, the contexts will be reused.

        TODO: If the package had variants, the test will be run for each
        variant.

        Returns:
            int: Returncode - zero if all test(s) passed, otherwise the return
                code of the failed test.
        """
        def print_header(txt, *nargs):
            pr = Printer(sys.stdout)
            pr(txt % nargs, heading)

        package = self.get_package()

        if test_name not in self.get_test_names():
            raise PackageTestError("Test '%s' not found in package %s"
                                   % (test_name, package.uri))

        if self.use_current_env:
            return self._run_test_in_current_env(test_name)

        for variant in package.iter_variants():

            # get test info for this variant. If None, that just means that this
            # variant doesn't provide this test. That's ok - 'tests' might be
            # implemented as a late function attribute that provides some tests
            # for some variants and not others
            #
            test_info = self._get_test_info(test_name, variant)
            if not test_info:
                continue

            command = test_info["command"]
            requires = test_info["requires"]

            # expand refs like {root} in commands
            if isinstance(command, basestring):
                command = variant.format(command)
            else:
                command = map(variant.format, command)

            # show progress
            if self.verbose:
                print_header(
                    "\nTest: %s\nPackage: %s\n%s\n",
                    test_name, variant.uri, '-' * 80)

            # create test env
            key = tuple(requires)
            context = self.contexts.get(key)

            if context is None:
                if self.verbose:
                    print_header("Resolving test environment: %s\n",
                                 ' '.join(map(quote, requires)))

                context = ResolvedContext(package_requests=requires,
                                          package_paths=self.package_paths,
                                          buf=self.stdout,
                                          timestamp=self.timestamp,
                                          **self.context_kwargs)

                if not context.success:
                    context.print_info(buf=self.stderr)
                    raise PackageTestError(
                        "Cannot run test '%s' of package %s: the environment "
                        "failed to resolve" % (test_name, variant.uri))

                self.contexts[key] = context

            # run the test in the context
            if self.verbose:
                context.print_info(self.stdout)

                if isinstance(command, basestring):
                    cmd_str = command
                else:
                    cmd_str = ' '.join(map(quote, command))

                print_header("\nRunning test command: %s\n" % cmd_str)

            retcode, _, _ = context.execute_shell(
                command=command,
                stdout=self.stdout,
                stderr=self.stderr,
                block=True)

            if retcode:
                return retcode

            # TODO FIXME we don't iterate over all variants yet, because we
            # can't reliably do that (see class docstring)
            break

        return 0  # success
Ejemplo n.º 17
0
    def execute(self, app_path, app_args, version, **kwargs):
        """Start the required application using rez if required.

        Notes:
            - Define variables used to bootstrap tank from overwrite on
              first reference
            - Define others within ``tk-multi-launchapp.yml`` file in the
              ``extra:rez:parent_variables`` list.

        Args:
            app_path (str):
                The path of the application executable
            app_args (str):
                Any arguments the application may require
            version (str):
                version of the application being run if set in the "versions"
                settings of the Launcher instance, otherwise ``None``

        Returns:
            dict[str]:
                Execute results mapped to 'command' (str) and
                'return_code' (int).
        """
        multi_launchapp = self.parent
        rez_info = multi_launchapp.get_setting("extra", {}).get("rez", {})
        cmd, shell_type = self.background_cmd_shell_type(app_path, app_args)

        # Execute App in a Rez context
        rez_py_path = self.get_rez_path()
        if rez_py_path:
            if rez_py_path not in sys.path:
                self.logger.debug('Appending to sys.path: "%s"', rez_py_path)
                sys.path.append(rez_py_path)

            # Only import after rez_py_path is inside sys.path
            from rez.resolved_context import ResolvedContext
            from rez.config import config

            rez_parent_variables = rez_info.get("parent_variables", [])
            rez_packages = [
                request.format(version=version)
                for request in rez_info.get("packages", [])
            ]
            self.logger.debug("rez parent variables: %s", rez_parent_variables)
            self.logger.debug("rez packages: %s", rez_packages)

            config.parent_variables = rez_parent_variables
            context = ResolvedContext(rez_packages)
            parent_env = self.create_shell_parent_env(context, config,
                                                      app_path, app_args,
                                                      version, **kwargs)

            env_kwargs = {"suffix": "-prev-env.py", "delete": False}
            with NamedTemporaryFile(mode="w+", **env_kwargs) as env_file:
                env_file.write(pformat(parent_env))
                self.logger.debug('Copied existing env for rez. See: "%s"',
                                  env_file.name)

            with TemporaryFile(mode="w+") as info_buffer:
                context.print_info(buf=info_buffer)
                info_buffer.seek(0)
                self.logger.debug(
                    "Executing in rez context [%s]: %s\n%s",
                    shell_type,
                    cmd,
                    info_buffer.read(),
                )

            launcher_process = context.execute_shell(
                command=cmd,
                parent_environ=parent_env,
                shell=shell_type,
                stdin=False,
                block=False,
            )
            exit_code = launcher_process.wait()
        else:
            # run the command to launch the app
            exit_code = subprocess.check_call(cmd)

        return {"command": cmd, "return_code": exit_code}