def resolve_context(self, verbosity=0, max_fails=-1, timestamp=None, callback=None, buf=None, package_load_callback=None): """Update the current context by performing a re-resolve. The newly resolved context is only applied if it is a successful solve. Returns: `ResolvedContext` object, which may be a successful or failed solve. """ package_filter = PackageFilterList.from_pod(self.package_filter) context = ResolvedContext( self.request, package_paths=self.packages_path, package_filter=package_filter, verbosity=verbosity, max_fails=max_fails, timestamp=timestamp, buf=buf, callback=callback, package_load_callback=package_load_callback, caching=self.caching) if context.success: if self._context and self._context.load_path: context.set_load_path(self._context.load_path) self._set_context(context) self._modified = True return context
def run_rez_shell(command, rez_pkg, weight=False): """Runs provided command inside rez-resolved shell. Args: command (str): custom command Returns: pid: Process object of subshell. Note: pid runs in separate process and needs to be waited with wait() command outside this function, if commad takes time. """ if not REZ_FOUND: print "Can't execute command in rez configured subshell." print "No rez package found! (does $REZ_CONFIG_FILE exist?) " return False from rez.resolved_context import ResolvedContext if not command: return self.EmtyProcess() context = ResolvedContext(rez_pkg) rez_pid = context.execute_command(command) return rez_pid
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
def test_caching_on_resolve(self): """Test that cache is updated as expected on resolved env.""" pkgcache = self._pkgcache() with restore_os_environ(): # set config settings into env so rez-pkg-cache proc sees them os.environ.update(self.get_settings_env()) # Creating the context will asynchronously add variants to the cache # in a separate proc. # c = ResolvedContext([ "timestamped-1.2.0", "pyfoo-3.1.0" # won't cache, see earlier test ]) variant = c.get_resolved_package("timestamped") # Retry 50 times with 0.1 sec interval, 5 secs is more than enough for # the very small variant to be copied to cache. # path = None for _ in range(50): time.sleep(0.1) path = pkgcache.get_cached_root(variant) if path: break self.assertNotEqual(path, None) expected_payload_file = os.path.join(path, "stuff.txt") self.assertTrue(os.path.exists(expected_payload_file))
def test_8(self): """Ensure that include modules are copied.""" self._reset_dest_repository() src_pkg = self._get_src_pkg("foo", "1.1.0") copy_package( package=src_pkg, dest_repository=self.dest_install_root, ) dest_pkg = self._get_dest_pkg("foo", "1.1.0") dest_variant = next(dest_pkg.iter_variants()) # do a resolve ctxt = ResolvedContext( ["foo==1.1.0"], package_paths=[self.dest_install_root, self.install_root] ) resolved_variant = ctxt.get_resolved_package("foo") self.assertEqual(dest_variant.handle, resolved_variant.handle) # this can only match if the include module was copied with the package environ = ctxt.get_environ(parent_environ={}) self.assertEqual(environ.get("EEK"), "2")
def _test_package(self, pkg, env, expected_commands): orig_environ = os.environ.copy() r = ResolvedContext([str(pkg)], caching=False) # this environ should not have changed self.assertEqual(orig_environ, os.environ) commands = r.get_actions(parent_environ=env) commands_ = [] # ignore some commands that don't matter or change depending on system ignore_keys = set([ "REZ_USED", "REZ_USED_VERSION", "REZ_USED_TIMESTAMP", "REZ_USED_REQUESTED_TIMESTAMP", "REZ_USED_PACKAGES_PATH", "REZ_USED_IMPLICIT_PACKAGES", "PATH" ]) for cmd in commands: if isinstance(cmd, (Comment, Shebang)): continue elif isinstance(cmd, EnvAction) and cmd.key in ignore_keys: continue else: commands_.append(cmd) self.assertEqual(commands_, expected_commands)
def test_8(self): """Ensure that include modules are copied.""" self._reset_dest_repository() src_pkg = self._get_src_pkg("foo", "1.1.0") copy_package( package=src_pkg, dest_repository=self.dest_install_root, ) dest_pkg = self._get_dest_pkg("foo", "1.1.0") dest_variant = dest_pkg.iter_variants().next() # do a resolve ctxt = ResolvedContext( ["foo==1.1.0"], package_paths=[self.dest_install_root, self.install_root] ) resolved_variant = ctxt.get_resolved_package("foo") self.assertEqual(dest_variant.handle, resolved_variant.handle) # this can only match if the include module was copied with the package environ = ctxt.get_environ(parent_environ={}) self.assertEqual(environ.get("EEK"), "2")
def _test_package(self, pkg, env, expected_commands): orig_environ = os.environ.copy() r = ResolvedContext([str(pkg)], caching=False) # this environ should not have changed self.assertEqual(orig_environ, os.environ) commands = r.get_actions(parent_environ=env) commands_ = [] # ignore some commands that don't matter or change depending on system ignore_keys = set(["REZ_USED", "REZ_USED_VERSION", "REZ_USED_TIMESTAMP", "REZ_USED_REQUESTED_TIMESTAMP", "REZ_USED_PACKAGES_PATH", "REZ_USED_IMPLICIT_PACKAGES", "PATH"]) for cmd in commands: if isinstance(cmd, (Comment, Shebang)): continue elif isinstance(cmd, EnvAction) and cmd.key in ignore_keys: continue else: commands_.append(cmd) self.assertEqual(commands_, expected_commands)
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)
def resolve_context(self, verbosity=0, max_fails=-1, timestamp=None, callback=None, buf=None, package_load_callback=None): """Update the current context by performing a re-resolve. The newly resolved context is only applied if it is a successful solve. Returns: `ResolvedContext` object, which may be a successful or failed solve. """ package_filter = PackageFilterList.from_pod(self.package_filter) context = ResolvedContext( self.request, package_paths=self.packages_path, package_filter=package_filter, verbosity=verbosity, max_fails=max_fails, timestamp=timestamp, buf=buf, callback=callback, package_load_callback=package_load_callback) if context.success: if self._context and self._context.load_path: context.set_load_path(self._context.load_path) self._set_context(context) self._modified = True return context
def test_apply(self): """Test apply() function.""" # Isolate our changes to os.environ and sys.path and return to the # original state to not mess with our test environment. with restore_os_environ(), restore_sys_path(): r = ResolvedContext(["hello_world"]) r.apply() self.assertEqual(os.environ.get("OH_HAI_WORLD"), "hello")
def test_serialize(self): """Test save/load of context.""" # save file = os.path.join(self.root, "test.rxt") r = ResolvedContext(["hello_world"]) r.save(file) # load r2 = ResolvedContext.load(file) self.assertEqual(r.resolved_packages, r2.resolved_packages)
def action_resolve(requests_or_rxt): from rez.resolved_context import ResolvedContext # noqa if os.path.isfile(requests_or_rxt): context = ResolvedContext.load(requests_or_rxt) else: context = ResolvedContext(requests_or_rxt.split(" ")) resolved_env = context.get_environ() resolved_env_str = json.dumps(resolved_env) _flush(resolved_env_str)
def test_execute_command(self): """Test command execution in context.""" if platform_.name == "windows": self.skipTest("This test does not run on Windows due to problems" " with the automated binding of the 'hello_world'" " executable.") r = ResolvedContext(["hello_world"]) p = r.execute_command(["hello_world"], stdout=subprocess.PIPE) stdout, _ = p.communicate() stdout = stdout.strip() self.assertEqual(stdout, "Hello Rez World!")
def test_execute_command(self): """Test command execution in context.""" if platform_.name == "windows": self.skipTest("This test does not run on Windows due to problems" " with the automated binding of the 'hello_world'" " executable.") r = ResolvedContext(["hello_world"]) p = r.execute_command(["hello_world"], stdout=subprocess.PIPE, text=True) stdout, _ = p.communicate() stdout = stdout.strip() self.assertEqual(stdout, "Hello Rez World!")
def test_2(self): """Test basic suite.""" c_foo = ResolvedContext(["foo"]) c_bah = ResolvedContext(["bah"]) s = Suite() s.add_context("foo", c_foo) s.add_context("bah", c_bah) expected_tools = set(["fooer", "bahbah", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.set_context_prefix("foo", "fx_") expected_tools = set(["fx_fooer", "bahbah", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.set_context_suffix("foo", "_fun") s.set_context_suffix("bah", "_anim") expected_tools = set( ["fx_fooer_fun", "bahbah_anim", "blacksheep_anim"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.remove_context("bah") expected_tools = set(["fx_fooer_fun"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.add_context("bah", c_bah) expected_tools = set(["fx_fooer_fun", "bahbah", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.alias_tool("bah", "blacksheep", "whitesheep") expected_tools = set(["fx_fooer_fun", "bahbah", "whitesheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) # explicit alias takes precedence over prefix/suffix s.alias_tool("foo", "fooer", "floober") expected_tools = set(["floober", "bahbah", "whitesheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.unalias_tool("foo", "fooer") s.unalias_tool("bah", "blacksheep") expected_tools = set(["fx_fooer_fun", "bahbah", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.hide_tool("bah", "bahbah") expected_tools = set(["fx_fooer_fun", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) s.unhide_tool("bah", "bahbah") expected_tools = set(["fx_fooer_fun", "bahbah", "blacksheep"]) self.assertEqual(set(s.get_tools().keys()), expected_tools) self._test_serialization(s)
def _get_resolved_path(self): # Add rez python module to sys.path self._append_sys_path_with_rez_loc() from rez.resolved_context import ResolvedContext context = ResolvedContext(self._packages) resolved_package = context.get_resolved_package(self._package) if not resolved_package: from pprint import pformat raise ImportError('Failed to resolve rez package for:\n{}'.format( pformat(self._descriptor_dict))) return os.path.normpath(resolved_package.root)
def test_create_context(self): """Test creation of context.""" r = ResolvedContext([]) r.print_info() r = ResolvedContext(["hello_world"]) r.print_info()
def test_bundled(self): """Test that a bundled context behaves identically.""" def _test_bundle(path): # load the bundled context r2 = ResolvedContext.load(os.path.join(path, "context.rxt")) # check the pkg we contain is in the bundled pkg repo variant = r2.resolved_packages[0] self.assertTrue( is_subdirectory(variant.root, path), "Expected variant root %r of variant %r to be a subdirectory of %r" % (variant.root, variant.uri, path)) self._test_execute_command_environ(r2) bundle_path = os.path.join(self.root, "bundle") # create context and bundle it r = ResolvedContext(["hello_world"]) bundle_context(context=r, dest_dir=bundle_path, force=True, verbose=True) # test the bundle _test_bundle(bundle_path) # copy the bundle and test the copy bundle_path2 = os.path.join(self.root, "bundle2") shutil.copytree(bundle_path, bundle_path2) _test_bundle(bundle_path2) # Create a bundle in a symlinked dest path. Bugs can arise where the # real path is used in some places and not others. # if platform.system().lower() in ("linux", "darwin"): hard_path = os.path.join(self.root, "foo") bundles_path = os.path.join(self.root, "bundles") bundle_path3 = os.path.join(bundles_path, "bundle3") os.mkdir(hard_path) os.symlink(hard_path, bundles_path) r = ResolvedContext(["hello_world"]) bundle_context(context=r, dest_dir=bundle_path3, force=True, verbose=True) _test_bundle(bundle_path3)
def create_context(pip_version=None, python_version=None): """Create a context containing the specific pip and python. Args: pip_version (str or `Version`): Version of pip to use, or latest if None. python_version (str or `Version`): Python version to use, or latest if None. Returns: `ResolvedContext`: Context containing pip and python. """ # determine pip pkg to use for install, and python variants to install on if pip_version: pip_req = "pip-%s" % str(pip_version) else: pip_req = "pip" if python_version: ver = Version(str(python_version)) major_minor_ver = ver.trim(2) py_req = "python-%s" % str(major_minor_ver) else: # use latest major.minor package = get_latest_package("python") if package: major_minor_ver = package.version.trim(2) else: # no python package. We're gonna fail, let's just choose current # python version (and fail at context creation time) major_minor_ver = '.'.join(map(str, sys.version_info[:2])) py_req = "python-%s" % str(major_minor_ver) # use pip + latest python to perform pip download operations request = [pip_req, py_req] with convert_errors(from_=(PackageFamilyNotFoundError, PackageNotFoundError), to=BuildError, msg="Cannot run - pip or python rez " "package is not present"): context = ResolvedContext(request) # print pip package used to perform the install pip_variant = context.get_resolved_package("pip") pip_package = pip_variant.parent print_info("Using %s (%s)" % (pip_package.qualified_name, pip_variant.uri)) return context
def create_context(pip_version=None, python_version=None): """Create a context containing the specific pip and python. Args: pip_version (str or `Version`): Version of pip to use, or latest if None. python_version (str or `Version`): Python version to use, or latest if None. Returns: `ResolvedContext`: Context containing pip and python. """ # determine pip pkg to use for install, and python variants to install on if pip_version: pip_req = "pip-%s" % str(pip_version) else: pip_req = "pip" if python_version: ver = Version(str(python_version)) major_minor_ver = ver.trim(2) py_req = "python-%s" % str(major_minor_ver) else: # use latest major.minor package = get_latest_package("python") if package: major_minor_ver = package.version.trim(2) else: # no python package. We're gonna fail, let's just choose current # python version (and fail at context creation time) major_minor_ver = ".".join(map(str, sys.version_info[:2])) py_req = "python-%s" % str(major_minor_ver) # use pip + latest python to perform pip download operations request = [pip_req, py_req] with convert_errors( from_=(PackageFamilyNotFoundError, PackageNotFoundError), to=BuildError, msg="Cannot run - pip or python rez " "package is not present", ): context = ResolvedContext(request) # print pip package used to perform the install pip_variant = context.get_resolved_package("pip") pip_package = pip_variant.parent print_info("Using %s (%s)" % (pip_package.qualified_name, pip_variant.uri)) return context
def test_serialize(self): """Test context serialization.""" # save file = os.path.join(self.root, "test.rxt") r = ResolvedContext(["hello_world"]) r.save(file) # load r2 = ResolvedContext.load(file) self.assertEqual(r.resolved_packages, r2.resolved_packages) # verify env = r2.get_environ() self.assertEqual(env.get("OH_HAI_WORLD"), "hello")
def _print_context_info(self, value, buf=sys.stdout, b=False): word = "is also" if b else "is" _pr = Printer(buf) path = os.path.abspath(value) if not os.path.isfile(path): return False try: ResolvedContext.load(path) except: return False _pr("'%s' %s a context. Use 'rez-context' for more information." % (path, word)) return True
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
def _FWD__spawn_build_shell(working_dir, build_path, variant_index, install, install_path=None): # This spawns a shell that the user can run the build command in directly context = ResolvedContext.load(os.path.join(build_path, "build.rxt")) package = get_developer_package(working_dir) variant = package.get_variant(variant_index) config.override("prompt", "BUILD>") actions_callback = functools.partial(CustomBuildSystem._add_build_actions, context=context, package=package, variant=variant, build_type=BuildType.local, install=install, build_path=build_path, install_path=install_path) post_actions_callback = functools.partial( CustomBuildSystem.add_pre_build_commands, variant=variant, build_type=BuildType.local, install=install, build_path=build_path, install_path=install_path) retcode, _, _ = context.execute_shell( block=True, cwd=build_path, actions_callback=actions_callback, post_actions_callback=post_actions_callback) sys.exit(retcode)
def application_parent_environment(): import os from rez.resolved_context import ResolvedContext rxt = os.getenv("REZ_RXT_FILE") if not rxt: return os.environ.copy() # Allzpark is launched from a Rez resolved context, need to compute the # original environment so the application can be launched in a proper # parent environment. # TODO: Load environment from "house" package (.env file) context = ResolvedContext.load(rxt) context.append_sys_path = False changes = context.get_environ() current = os.environ.copy() rollbacked = dict() for key, value in current.items(): current_paths = value.split(os.pathsep) changed_paths = changes.get(key, "").split(os.pathsep) roll_paths = [] for path in current_paths: if path and path not in changed_paths: roll_paths.append(path) if roll_paths: rollbacked[key] = os.pathsep.join(roll_paths) return rollbacked
def re_resolve_rxt(context): """Re-resolve context loaded from .rxt file This takes following entries from input context to resolve a new one: - package_requests - timestamp - package_paths - package_filters - package_orderers - building :param context: .rxt loaded context :type context: ResolvedContext :return: new resolved context :rtype: ResolvedContext :raises AssertionError: If no context.load_path (not loaded from .rxt) """ assert context.load_path, "Not a loaded context." rxt = context return ResolvedContext( package_requests=rxt.requested_packages(), timestamp=rxt.requested_timestamp, package_paths=rxt.package_paths, package_filter=rxt.package_filter, package_orderers=rxt.package_orderers, building=rxt.building, )
def __init__(self, filepath): """Create a wrapper given its executable file.""" from rez.suite import Suite def _err(msg): raise RezSystemError("Invalid executable file %s: %s" % (filepath, msg)) with open(filepath) as f: content = f.read() try: doc = yaml.load(content) doc = doc["kwargs"] context_name = doc["context_name"] tool_name = doc["tool_name"] prefix_char = doc.get("prefix_char") except YAMLError as e: _err(str(e)) # check that the suite is there - a wrapper may have been moved out of # a suite's ./bin path, which renders it useless. suite_path = os.path.dirname(os.path.dirname(filepath)) try: Suite.load(suite_path) except SuiteError as e: _err(str(e)) path = os.path.join(suite_path, "contexts", "%s.rxt" % context_name) context = ResolvedContext.load(path) self._init(suite_path, context_name, context, tool_name, prefix_char)
def _FWD__spawn_build_shell(working_dir, build_dir): # This spawns a shell that the user can run 'bez' in directly context = ResolvedContext.load(os.path.join(build_dir, "build.rxt")) config.override("prompt", "BUILD>") retcode, _, _ = context.execute_shell(block=True, cwd=build_dir) sys.exit(retcode)
def get_package(self): """Get the target package. Returns: `Package`: Package to run tests on. """ if self.package is not None: return self.package if self.use_current_env: # get package from current context, or return None current_context = ResolvedContext.get_current() if current_context is None: return None req = Requirement(self.package_request) variant = current_context.get_resolved_package(req.name) if variant is None: return None package = variant.parent if not req.range.contains_version(package.version): return None else: # find latest package within request package = get_latest_package_from_string(str(self.package_request), self.package_paths) if package is None: raise PackageNotFoundError("Could not find package to test: %s" % str(self.package_request)) self.package = package return self.package
def __init__(self, filepath): """Create a wrapper given its executable file.""" from rez.suite import Suite def _err(msg): raise RezSystemError("Invalid executable file %s: %s" % (filepath, msg)) with open(filepath) as f: content = f.read() try: doc = yaml.load(content, Loader=yaml.FullLoader) doc = doc["kwargs"] context_name = doc["context_name"] tool_name = doc["tool_name"] prefix_char = doc.get("prefix_char") except YAMLError as e: _err(str(e)) # check that the suite is there - a wrapper may have been moved out of # a suite's ./bin path, which renders it useless. suite_path = os.path.dirname(os.path.dirname(filepath)) try: Suite.load(suite_path) except SuiteError as e: _err(str(e)) path = os.path.join(suite_path, "contexts", "%s.rxt" % context_name) context = ResolvedContext.load(path) self._init(suite_path, context_name, context, tool_name, prefix_char)
def setUpClass(cls): TempdirMixin.setUpClass() cls.settings = dict() cls.tempdir = tempfile.mkdtemp() python = which("python") assert python, "No Python found" result = subprocess.check_output( [python, "--version"], universal_newlines=True, stderr=subprocess.STDOUT, ) _, version = result.rstrip().split(" ", 1) version = version.split()[-1] version = int(version[0]) with make_package("python", cls.tempdir) as maker: PATH = os.path.dirname(python).replace("\\", "/") maker.version = str(version) maker.commands = "\n".join(["env.PATH.prepend(r'%s')" % PATH]) cls.context = ResolvedContext(["python"], package_paths=[cls.tempdir]) cls.python_version = version
def test_retarget(self): """Test that a retargeted context behaves identically.""" # make a copy of the pkg repo packages_path2 = os.path.join(self.root, "packages2") shutil.copytree(self.packages_path, packages_path2) # create a context, retarget to pkg repo copy r = ResolvedContext(["hello_world"]) r2 = r.retargeted(package_paths=[packages_path2]) # check the pkg we contain is in the copied pkg repo variant = r2.resolved_packages[0] self.assertTrue(is_subdirectory(variant.root, packages_path2)) self._test_execute_command_environ(r2)
def test_caching_on_resolve(self): """Test that cache is updated as expected on resolved env.""" pkgcache = self._pkgcache() with restore_os_environ(): # set config settings into env so rez-pkg-cache proc sees them os.environ.update(self.get_settings_env()) # Creating the context will asynchronously add variants to the cache # in a separate proc. # c = ResolvedContext([ "timestamped-1.2.0", "pyfoo-3.1.0" # won't cache, see earlier test ]) variant = c.get_resolved_package("timestamped") # Retry 50 times with 0.1 sec interval, 5 secs is more than enough for # the very small variant to be copied to cache. # cached_root = None for _ in range(50): time.sleep(0.1) cached_root = pkgcache.get_cached_root(variant) if cached_root: break self.assertNotEqual(cached_root, None) expected_payload_file = os.path.join(cached_root, "stuff.txt") self.assertTrue(os.path.exists(expected_payload_file)) # check that refs to root point to cache location in rex code for ref in ("resolve.timestamped.root", "'{resolve.timestamped.root}'"): proc = c.execute_rex_code(code="info(%s)" % ref, stdout=subprocess.PIPE, universal_newlines=True) out, _ = proc.communicate() root = out.strip() self.assertEqual( root, cached_root, "Reference %r should resolve to %s, but resolves to %s" % (ref, cached_root, root))
def context(self): """Get the current context. Returns: `ResolvedContext` or None if not in a context. """ path = self.context_file return ResolvedContext.load(path) if path else None
def test_execute_command_environ(self): """Test that execute_command properly sets environ dict.""" parent_environ = {"BIGLY": "covfefe"} r = ResolvedContext(["hello_world"]) pycode = ("import os; " "print os.getenv(\"BIGLY\"); " "print os.getenv(\"OH_HAI_WORLD\")") args = ["python", "-c", pycode] p = r.execute_command(args, parent_environ=parent_environ, stdout=subprocess.PIPE) stdout, _ = p.communicate() stdout = stdout.strip() parts = [x.strip() for x in stdout.split('\n')] self.assertEqual(parts, ["covfefe", "hello"])
def test_execute_command_environ(self): """Test that execute_command properly sets environ dict.""" parent_environ = {"BIGLY": "covfefe"} r = ResolvedContext(["hello_world"]) pycode = ("import os; " "print(os.getenv(\"BIGLY\")); " "print(os.getenv(\"OH_HAI_WORLD\"))") args = ["python", "-c", pycode] p = r.execute_command(args, parent_environ=parent_environ, stdout=subprocess.PIPE) stdout, _ = p.communicate() stdout = stdout.strip() parts = [x.strip() for x in stdout.decode("utf-8").split('\n')] self.assertEqual(parts, ["covfefe", "hello"])
def _FWD__invoke_suite_tool_alias(context_name, tool_name, _script, _cli_args): suite_path = os.path.dirname(os.path.dirname(_script)) path = os.path.join(suite_path, "contexts", "%s.rxt" % context_name) context = ResolvedContext.load(path) from rez.wrapper import Wrapper w = Wrapper.__new__(Wrapper) w._init(suite_path, context_name, context, tool_name) retcode = w.run(*_cli_args) sys.exit(retcode)
def _FWD__invoke_suite_tool_alias(context_name, tool_name, prefix_char=None, _script=None, _cli_args=None): suite_path = os.path.dirname(os.path.dirname(_script)) path = os.path.join(suite_path, "contexts", "%s.rxt" % context_name) context = ResolvedContext.load(path) from rez.wrapper import Wrapper w = Wrapper.__new__(Wrapper) w._init(suite_path, context_name, context, tool_name, prefix_char) retcode = w.run(*(_cli_args or [])) sys.exit(retcode)
def get_package_info(path, variant_index): """ Get valuable information about a package that can be used in different contexts. :param path: Path to the root of a project :param variant: index of the variant to resolve :return: Dict with various info about a package """ data = { "variants": [], } package = get_developer_package(path) variants = list(package.iter_variants()) for v in variants: data["variants"].append(v.qualified_name) variant = variants[variant_index] request = variant.get_requires(build_requires=True, private_build_requires=True) context = ResolvedContext(request) data["name"] = package.name data["interpreter"] = context.which("python") data["dependencies"] = get_dependencies(context) return data
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
def _FWD__spawn_build_shell(working_dir, build_dir, variant_index): # This spawns a shell that the user can run 'make' in directly context = ResolvedContext.load(os.path.join(build_dir, "build.rxt")) package = get_developer_package(working_dir) variant = package.get_variant(variant_index) config.override("prompt", "BUILD>") callback = functools.partial(CMakeBuildSystem._add_build_actions, context=context, package=package, variant=variant, build_type=BuildType.local) retcode, _, _ = context.execute_shell(block=True, cwd=build_dir, actions_callback=callback) sys.exit(retcode)
def load_context(self, filepath): context = None busy_cursor = QtGui.QCursor(QtCore.Qt.WaitCursor) with self.status("Loading %s..." % filepath): QtGui.QApplication.setOverrideCursor(busy_cursor) try: context = ResolvedContext.load(filepath) except ResolvedContextError as e: QtGui.QMessageBox.critical(self.main_window, "Failed to load context", str(e)) finally: QtGui.QApplication.restoreOverrideCursor() if context: path = os.path.realpath(filepath) self.config.prepend_string_list("most_recent_contexts", path, "max_most_recent_contexts") return context
def context(self, name): """Get a context. Args: name (str): Name to store the context under. Returns: `ResolvedContext` object. """ data = self._context(name) context = data.get("context") if context: return context assert self.load_path context_path = os.path.join(self.load_path, "contexts", "%s.rxt" % name) context = ResolvedContext.load(context_path) data["context"] = context data["loaded"] = True return context
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)
def test_apply(self): """Test apply() function.""" r = ResolvedContext(["hello_world"]) r.apply() self.assertEqual(os.environ.get("OH_HAI_WORLD"), "hello")
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
def _run(self, prefix_char, args): from rez.vendor import argparse parser = argparse.ArgumentParser(prog=self.tool_name, prefix_chars=prefix_char) def _add_argument(*nargs, **kwargs): nargs_ = [] for narg in nargs: nargs_.append(narg.replace('=', prefix_char)) parser.add_argument(*nargs_, **kwargs) _add_argument( "=a", "==about", action="store_true", help="print information about the tool") _add_argument( "=i", "==interactive", action="store_true", help="launch an interactive shell within the tool's configured " "environment") _add_argument( "=p", "==patch", type=str, nargs='*', metavar="PKG", help="run the tool in a patched environment") _add_argument( "==versions", action="store_true", help="list versions of package providing this tool") _add_argument( "==command", type=str, nargs='+', metavar=("COMMAND", "ARG"), help="read commands from string, rather than executing the tool") _add_argument( "==stdin", action="store_true", help="read commands from standard input, rather than executing the tool") _add_argument( "==strict", action="store_true", help="strict patching. Ignored if ++patch is not present") _add_argument( "==nl", "==no-local", dest="no_local", action="store_true", help="don't load local packages when patching") _add_argument( "==peek", action="store_true", help="diff against the tool's context and a re-resolved copy - " "this shows how 'stale' the context is") _add_argument( "==verbose", action="count", default=0, help="verbose mode, repeat for more verbosity") _add_argument( "==quiet", action="store_true", help="hide welcome message when entering interactive mode") _add_argument( "==no-rez-args", dest="no_rez_args", action="store_true", help="pass all args to the tool, even if they start with '%s'" % prefix_char) opts, tool_args = parser.parse_known_args(args) if opts.no_rez_args: args = list(args) args.remove("==no-rez-args".replace('=', prefix_char)) tool_args = args opts = parser.parse_args([]) # print info if opts.about: return self.print_about() elif opts.versions: return self.print_package_versions() elif opts.peek: return self.peek() # patching context = self.context if opts.patch is not None: new_request = opts.patch request = context.get_patched_request(new_request, strict=opts.strict) config.remove_override("quiet") pkg_paths = (config.nonlocal_packages_path if opts.no_local else None) context = ResolvedContext(request, package_paths=pkg_paths, verbosity=opts.verbose) # reapply quiet mode (see cli.forward) if "REZ_QUIET" not in os.environ: config.override("quiet", True) if opts.stdin: # generally shells will behave as though the '-s' flag was not present # when no stdin is available. So here we replicate this behaviour. import select if not select.select([sys.stdin], [], [], 0.0)[0]: opts.stdin = False # construct command cmd = None if opts.command: cmd = opts.command elif opts.interactive: label = self.context_name if opts.patch: label += '*' config.override("prompt", "%s>" % label) cmd = None else: cmd = [self.tool_name] + tool_args retcode, _, _ = context.execute_shell(command=cmd, stdin=opts.stdin, quiet=opts.quiet, block=True) return retcode
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 }
def command(opts, parser, extra_arg_groups=None): from rez.suite import Suite from rez.status import status from rez.exceptions import SuiteError from rez.resolved_context import ResolvedContext import sys context_needed = set(("add", "prefix", "suffix", "hide", "unhide", "alias", "unalias", "interactive")) save_needed = set(("add", "remove", "bump", "prefix", "suffix", "hide", "unhide", "alias", "unalias")) def _pr(s): if opts.verbose: print s def _option(name): value = getattr(opts, name) if value and name in context_needed and not opts.context: parser.error("--context must be supplied when using --%s" % name.replace('_', '-')) return value if opts.list: suites = status.suites if suites: for suite in suites: print suite.load_path else: print "No visible suites." sys.exit(0) if not opts.DIR: parser.error("DIR required.") if opts.create: suite = Suite() _pr("create empty suite at %r..." % opts.DIR) suite.save(opts.DIR) # raises if dir already exists sys.exit(0) suite = Suite.load(opts.DIR) if _option("interactive"): context = suite.context(opts.context) retcode, _, _ = context.execute_shell(block=True) sys.exit(retcode) elif _option("validate"): try: suite.validate() except SuiteError as e: print >> sys.stderr, "The suite is invalid:\n%s" % str(e) sys.exit(1) print "The suite is valid." elif _option("find_request") or _option("find_resolve"): context_names = suite.find_contexts(in_request=opts.find_request, in_resolve=opts.find_resolve) if context_names: print '\n'.join(context_names) elif _option("print_tools"): suite.print_tools(verbose=opts.verbose, context_name=opts.context) elif _option("add"): _pr("loading context at %r..." % opts.add) context = ResolvedContext.load(opts.add) _pr("adding context %r..." % opts.context) suite.add_context(name=opts.context, context=context, prefix_char=opts.prefix_char) elif _option("remove"): _pr("removing context %r..." % opts.remove) suite.remove_context(name=opts.remove) elif _option("bump"): _pr("bumping context %r..." % opts.bump) suite.bump_context(name=opts.bump) elif _option("prefix"): _pr("prefixing context %r..." % opts.context) suite.set_context_prefix(name=opts.context, prefix=opts.prefix) elif _option("suffix"): _pr("suffixing context %r..." % opts.context) suite.set_context_suffix(name=opts.context, suffix=opts.suffix) elif _option("hide"): _pr("hiding tool %r in context %r..." % (opts.hide, opts.context)) suite.hide_tool(context_name=opts.context, tool_name=opts.hide) elif _option("unhide"): _pr("unhiding tool %r in context %r..." % (opts.unhide, opts.context)) suite.unhide_tool(context_name=opts.context, tool_name=opts.unhide) elif _option("alias"): _pr("aliasing tool %r as %r in context %r..." % (opts.alias[0], opts.alias[1], opts.context)) suite.alias_tool(context_name=opts.context, tool_name=opts.alias[0], tool_alias=opts.alias[1]) elif _option("unalias"): _pr("unaliasing tool %r in context %r..." % (opts.unalias, opts.context)) suite.unalias_tool(context_name=opts.context, tool_name=opts.unalias) elif _option("which"): filepath = suite.get_tool_filepath(opts.which) if filepath: print filepath sys.exit(0) else: sys.exit(1) elif opts.context: context = suite.context(opts.context) context.print_info(verbosity=opts.verbose) else: suite.print_info(verbose=opts.verbose) sys.exit(0) do_save = any(getattr(opts, x) for x in save_needed) if do_save: _pr("saving suite to %r..." % opts.DIR) suite.save(opts.DIR)
def command(opts, parser, extra_arg_groups=None): from rez.status import status from rez.utils.formatting import columnise, PackageRequest from rez.resolved_context import ResolvedContext from rez.utils.graph_utils import save_graph, view_graph, prune_graph from pprint import pformat rxt_file = opts.RXT if opts.RXT else status.context_file if not rxt_file: print >> sys.stderr, "not in a resolved environment context." sys.exit(1) if rxt_file == '-': # read from stdin rc = ResolvedContext.read_from_buffer(sys.stdin, 'STDIN') else: rc = ResolvedContext.load(rxt_file) def _graph(): if rc.has_graph: return rc.graph(as_dot=True) else: print >> sys.stderr, "The context does not contain a graph." sys.exit(1) parent_env = {} if opts.no_env else None if not opts.interpret: if opts.print_request: print " ".join(str(x) for x in rc.requested_packages(False)) elif opts.print_resolve: print ' '.join(x.qualified_package_name for x in rc.resolved_packages) elif opts.tools: rc.print_tools() elif opts.diff: rc_other = ResolvedContext.load(opts.diff) rc.print_resolve_diff(rc_other, True) elif opts.fetch: rc_new = ResolvedContext(rc.requested_packages(), package_paths=rc.package_paths, verbosity=opts.verbose) rc.print_resolve_diff(rc_new, heading=("current", "updated")) elif opts.which: cmd = opts.which path = rc.which(cmd, parent_environ=parent_env) if path: print path else: print >> sys.stderr, "'%s' not found in the context" % cmd elif opts.print_graph: gstr = _graph() print gstr elif opts.graph or opts.write_graph: gstr = _graph() if opts.prune_pkg: req = PackageRequest(opts.prune_pkg) gstr = prune_graph(gstr, req.name) func = view_graph if opts.graph else save_graph func(gstr, dest_file=opts.write_graph) else: rc.print_info(verbosity=opts.verbose, source_order=opts.source_order, show_resolved_uris=opts.show_uris) return if opts.format == 'table': env = rc.get_environ(parent_environ=parent_env) rows = [x for x in sorted(env.iteritems())] print '\n'.join(columnise(rows)) elif opts.format == 'dict': env = rc.get_environ(parent_environ=parent_env) print pformat(env) else: code = rc.get_shell_code(shell=opts.format, parent_environ=parent_env, style=OutputStyle[opts.style]) print code