Ephemerals#
New in version 2.71.0.
Ephemeral packages (or simply ‘ephemerals’) are requests for packages that do not
exist. Ephemeral package names always begin with a dot (.
). Like all package
requests, ephemerals can be requested as part of packages’ requires or variants
lists, or directly by the user (via rez-env for eg).
Example:
]$ rez-env .foo-1
You are now in a rez-configured environment.
resolved by ajohns@turtle, on Tue Dec 22 08:17:00 2020, using Rez v2.70.0
requested packages:
.foo-1 (ephemeral)
~platform==linux (implicit)
~arch==x86_64 (implicit)
~os==Ubuntu-16.04 (implicit)
resolved packages:
.foo-1 (ephemeral)
Ephemerals will act like real packages during a resolve (ie, their request ranges will intersect, and conflicts can occur) but they never actually correlate to a real package, nor do they perform any configuration on the runtime (not directly in any case).
Example showing range intersection:
]$ rez-env .foo-1 '.foo-1.5+'
You are now in a rez-configured environment.
resolved by ajohns@turtle, on Tue Dec 22 08:21:04 2020, using Rez v2.70.0
requested packages:
.foo-1 (ephemeral)
.foo-1.5+ (ephemeral)
~platform==linux (implicit)
~arch==x86_64 (implicit)
~os==Ubuntu-16.04 (implicit)
resolved packages:
.foo-1.5+<1_ (ephemeral)
Example of conflicting request:
]$ rez-env .foo-1 .foo-2
The context failed to resolve:
The following package conflicts occurred: (.foo-1 <--!--> .foo-2)
Environment Variables#
Ephemerals do not affect the runtime in the way that packages can (via their
commands()
section), however some environment variables are set:
The following example illustrates:
]$ rez-env python .foo-1 .bah-2
...
]$ echo $REZ_EPH_FOO_REQUEST
1
]$ echo $REZ_USED_EPH_RESOLVE
.foo-1 .bah-2
Introspection#
In order for a package to inspect the ephemerals that are present in a runtime,
there is an ephemerals
object provided, similar
to the resolve
object. You would typically use the
intersects()
function to inspect it, like so:
# in package.py
def commands()
if intersects(ephemerals.get_range('enable_tracking', '0'), '1'):
env.TRACKING_ENABLED = 1
In this example, the given package would set the TRACKING_ENABLED
environment
variable if an ephemeral such as .enable_tracking-1
(or .enable_tracking-1.2+
etc) is present in the resolve. Note that the leading .
is implied and not
included when querying the ephemerals
object.
Warning
Since ephemerals
is a dict-like object, so it has
a get
function which will return a full request string if key exists. Hence,
the default value should also be a full request string, not just a version range
string like 0
in ephemerals.get_range()
. Or intersects()
may not work as expect.
Ephemeral Use Cases#
Why would you want to request packages that don’t exist? There are two main use cases.
Passing Information to Packages#
Ephemerals can be used as a kind of ‘package option’, or a way to pass information to packages in a resolve. For example, consider the following package definition:
name = 'bah'
def commands():
if intersects(ephemerals.get_range('bah.cli', '1'), '1'):
env.PATH.append('{root}/bin')
This package will disable its command line tools if an ephemeral like .bah.cli-0
is present in the runtime.
Note
Ephemerals are standard package requests and so can
have any range, such as 1.2.3
, 2.5+
and so on. However, they’re often used
as boolean package options, as in the example above. In this case, it is
recommended to use the conventional ranges 1
and 0
to designate true and
false.
Since ephemerals can be pretty much anything, you might also decide to use them
as a global package option. Here’s another take on our example, but in this case
we introduce a .cli
ephemeral that acts as a global whitelist:
name = 'bah'
def commands():
if intersects(ephemerals.get_range('cli', ''), 'bah'):
env.PATH.append('{root}/bin')
Here, all packages’ cli will be enabled if .cli
is not specified, but if it is
specified then it acts as a whitelist:
# turn on cli for foo and bah only
]$ rez-env foo-1 bah==2.3.1 eek-2.4 '.cli-foo|bah'
Abstract Package Representation#
Sometimes it makes sense for a package to require some form of abstract object or
capability, rather than an actual package. For example, perhaps your package (or
one of its variants) requires a GPU to be present on the host machine. To support
this, you might have something setup that includes a .gpu-1
ephemeral in the
implicits list on all GPU-enabled hosts.
Then, your package could look like this:
name = 'pixxelator'
variants = [
['.gpu-0'], # renders via CPU
['.gpu-1'] # renders via GPU
]
Warning
Be aware that on hosts that do not have a gpu
implicit, either variant could be selected. You would want to either guarantee
that every host has the gpu implicit set to 0 or 1, or that the user always
explicitly specifies .gpu-0
or .gpu-1
in their request.