Package Orderers¶
Rez’s default version resolution algorithm will always sort by the latest alphanumeric version. However, package orderers allow you to customize this functionality globally, or at a per package level.
This can be used to ensure that specific version have priority over others. Higher versions can still be accessed if explicitly requested.
Configuration¶
Package orderers can be configured in the rezconfig.py via the package_orderers setting.
Types¶
These are the available built-in orderers.
sorted¶
This is the default orderer that sorts based on the package’s version attribute.
You can optionally explicitly request this orderer like this:
package_orderers = [
{
"type": "sorted", # Required
"descending": True, # Required
"packages": ["python"] # Optional, if not supplied, orderer applies to all packages
}
]
version_split¶
This orderer orders all package versions less than or equal to a given version first, then sorts by the default sorted order.
For example, given the versions [5, 4, 3, 2, 1], an orderer initialized with version=3 would give the order [3, 2, 1, 5, 4].
package_orderers = [
{
"type": "version_split",
"first_version": "2.7.16"
}
]
A common use case is to ease migration from python-2 to python-3:
package_orderers = [
{
"type": "per_family",
"orderers": [
{
"packages": ["python"],
"type": "version_split",
"first_version": "2.7.16"
}
]
}
]
This will ensure that for the “python” package, versions equals or lower than “2.7.16” will have priority. Considering the following versions: “2.7.4”, “2.7.16”, “3.7.4”:
Example |
Result |
|---|---|
rez-env python |
python-2.7.16 |
rez-env python-3 |
python-3.7.4 |
Package orderers will also apply to variants of packages.
Consider a package “pipeline-1.0” which has the following variants:
[["python-2.7.4", "python-2.7.16", "python-3.7.4"]]
Example |
Result |
|---|---|
rez-env pipeline |
pipeline-1.0 python-2.7.16 |
rez-env pipeline python-3 |
pipeline-1.0 python-3.7.4 |
per_family¶
This orderer allows you to define different orderers to different package families.
package_orderers = [
{
"type": "per_family",
"orderers": [
{
"packages": ["python"],
"type": "version_split",
"first_version": "2.7.16"
}
]
}
]
soft_timestamp¶
This orderer takes in a given time T and returns packages released before T, in descending order, followed by
those released after.
If rank is non-zero, version changes at that rank and above are allowed over the timestamp.
A timestamp can be generated with python:
$ python -c "import datetime, time; print(int(time.mktime(datetime.date(2019, 9, 9).timetuple())))"
1568001600
The following example will prefer package released before 2019-09-09.
package_orderers = [
{
"type": "soft_timestamp",
"timestamp": 1568001600, # 2019-09-09
"rank": 3
}
]
The rank can be used to allow some versions released after the timestamp to still be considered. When using semantic versionnng, a value of 3 is the most common. This will let version with a different patch number to be accepted.
Considering a package “foo” with the following versions:
“1.0.0” was released at 2019-09-07
“2.0.0” was released at 2019-09-08
“2.0.1” was released at 2019-09-10
“2.1.0” was released at 2019-09-11
“3.0.0” was released at 2019-09-12
the following talbes shows the effect of rank:
Example |
Timestamp |
Rank |
Result |
|---|---|---|---|
rez-env foo |
2019-09-09 |
0 |
foo-2.0.0 |
rez-env foo |
2019-09-09 |
3 |
foo-2.0.1 |
rez-env foo |
2019-09-09 |
2 |
foo-2.1.0 |
rez-env foo |
2019-09-09 |
1 |
foo-3.0.0 |
no_order¶
An orderer that does not change the order - a no op.
This orderer is useful in cases where you want to apply some default orderer
to a set of packages, but may want to explicitly NOT reorder a particular
package. You would use a rez.package_order.NullPackageOrder in a rez.package_order.PerFamilyOrder to do this.
Custom orderers¶
It is possible to create custom orderers using the API. This can be achieved
by subclassing rez.package_order.PackageOrder and implementing some mandatory
methods. Once that’s done, you need to register the orderer using rez.package_order.register_orderer().
Note
Implementing a custom orderer should only be done if absolutely necessary. It could make your environment behave in very special ways and more importantly in non expected ways from a user perspective. It can also make it harder to share the set of affected packages to others.
from rez.version import Version
from rez.package_order import PackageOrder, register_orderer
class MyOrderer(PackageOrder):
name = "my_orderer"
def __init__(self, custom_arg: str, **kwargs):
super().__init__(self, **kwargs)
self.custom_arg = custom_arg
def sort_key_implementation(self, package_name: str, version: Version):
pass
def __str__(self):
pass
def __eq__(self, other):
pass
def to_pod(self, other):
pass
@classmethod
def from_pod(cls, data):
pass
register_orderer(MyOrderer)
package_orderers = [
{
"type": "my_orderer",
"custom_arg": "value here"
}
]
For more details, please see src/rez/package_order.py.