Rez中文文档04 Basic Concepts

概述

Rez管理软件包的过程:
首先从rez请求一个软件包列表,rez会对包进行解析。
如果解析没有成功,则系统会给出相关信息提示。
当请求的软件包版本发生冲突的时候,Rez也会给出提示。

  • “…the latest version of houdini”
  • “…maya-2009.1”
  • “…the latest rv and the latest maya and houdini-11.something”
  • “…rv-3.something or greater”
  • “…the latest houdini which works with boost-1.37.0”
  • “…PyQt-2.2 or greater, but less than PyQt-4.5.3”

在本文许多示例中,我们会使用rez-env命令行工具。
该工具获取软件包请求列表,并创建结果配置环境。
exit命令即可退出环境。

版本

Rez对版本号格式的支持:
数字,字母,和下划线的任意组合,并用点或破折号分隔。

有效的格式:

  • 1
  • 1.0.0
  • 3.2.build_13
  • 4.rc1
  • 10a-5

版本号遵循严格排序方式,区别大小写。
下划线为最小字符,后跟字母,再后跟数字。

  • 在所有字符之前添加下划线
  • 字母需要在数字之前
  • 大写字母在小写字母之前
  • 当数字0在版本号前,比较时’01’是小于’1’的
  • 如果版本号包含字母和数字组合,它会被切分成只包含数字和字包含字母的组,然后根据上述规则进行比较。

下面展示了一些版本对比的例子:

smaller token larger token
0 1
a b
a A
a 3
_5 2
ham hamster
alpha beta
alpha bob
02 2
002 02
13 043
3 3a
beta3 3beta

在进行版本比较的时候,分隔符(通常是.或者-符号)都会被忽略。
因此版本”1.0.0”和”1-0.0”是等同的。
如果两个版本通过数字对比相同,比如”1.0.0”和”1.0”,
则字符长度更长的版本被判断为更高版本。

注意:在进行版本对比中,rez版本号中字母并没有特殊意义,
比如”alpha”和”beta”。所以我们更多的鼓励使用数字来标记版本。

软件包

定义软件包的文件为package.py ,它描述了软件包所有的信息。
rez可以通过它管理任何类型的包,无论是Python程序包,
已编译的程序包,还是仅构建代码或者配置数据。

下面一个package文件的范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name = "foo"

version = "1.0.0"

description = "Something that does foo-like things."

requires = [
"python-2.6",
"utils-1.1+<2"
]

tools = [
"fooify"
]

def commands():
env.PYTHONPATH.append("{root}/python")
env.PATH.append("{root}/bin")
  • requires部分定义了软件包的要求。
  • command部分描述该程序包添加到环境中所执行的一些操作(如为环境添加变量)。

软件包存储库

软件包存储在磁盘中,位置在$PATH/package。看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/packages/inhouse/foo/1.1
/1.2
/1.3
/packages/inhouse/bah/2
/3
/4
/packages/inhouse/eek/2.5
/2.6
/2.7

# more detailed example of foo-1.1
/packages/inhouse/foo/1.1/package.py
/python/<PYTHON FILES>
/bin/<EXECUTABLES>

可以从上述层级结构中看到,package.py文件始终在该程序包的版本目录下。

Rez仅要求package.py 文件位于软件包安装根目录下,包的其余部分取决与软件自己的构建。

软件包搜索路径

Rez搜索路径查找软件包的方式和python使用PYTHONPATH查找python模块的方式几乎一样。

可以使用rez-config命令来返回搜索路径的列表:

1
2
3
4
]$ rez-config packages_path
- /home/ajohns/packages
- /packages/inhouse
- /packages/vendor

如果同一个软件包出现在搜索路径重复出现,会优先使用创建时间较早的那一个。

上述的搜索路径配置是一个经典设计:顺序从本地路径到服务器中央存储路径。
将其放在搜索路径的开头,可以方便开发人员优先用本地路径进行软件包的测试。

一种常见的修改软件包路径的方法是设置REZ_PACKAGES_PATH环境变量。

软件包命令

软件包定义的命令确定如何配置环境以使用它。

这是一个python函数,注意如果使用了任何导入操作,则必须在此函数的主体内。

1
2
3
def commands():
env.PYTHONPATH.append("{root}/python")
env.PATH.append("{root}/bin")

这是一个常用的配置示例,将软件包的源路径添加到PYTHONPATH,将其工具添加到PATH中。

关于包命令更多信息见:Package Commands

软件包请求

软件包对版本的请求使用一个特殊的语法,可以在package文件的require部分去定义,
也可以如rez-env之类的工具,创建配置环境的时候直接定义软件包请求。

举个例子,创建一个环境,包含python2.6或更高版本,以及my_py_utils5.4或更高版本,且版本不能大于6。
rez-env 'python-2.6+' 'my_py_utils-5.4+<6'

这里有一些使用的示例:

package request description example versions within request
foo Any version of foo. foo-1, foo-0.4, foo-5.0, foo-2.0.alpha
foo-1 Any version of foo-1[.x.x…x]. foo-1, foo-1.0, foo-1.2.3
foo-1+ foo-1 or greater. foo-1, foo-1.0, foo-1.2.3, foo-7.0.0
foo-1.2+<2 foo-1.2 or greater, but less than 2 foo-1.2.0, foo-1.6.4, foo-1.99
foo<2 Any version of foo less than 2 foo-1, foo-1.0.4
foo==2.0.0 Only version 2.0.0 exactly foo-2.0.0
foo-1.3|5+ OR’d requests foo-1.3.0, foo-6.0.0

Conflict运算符

!符号用于指定不希望出现的版本(用于定义软件包之间的不兼容性),命令:
rez-env maya_utils '!maya-2015.6'

这指定您需要任何版本的maya_utils,但不接受2015.6(包括2015.6.1等)之内的任何版本的maya。

Weak reference运算符

符号,它将强制软件包在指定范围内,但实际上并不需要这个软件包。
rez-env foo '~nuke-9.rc2'

这个请求也许会或者不会拉入nuke软件包,但是如果存在nuke的话,它的版本必须是9.rc2内。

弱引用在某些情况下有用,比如nuke和maya之类的软件都自带自己的python版本。
它们的软件对python没有要求。但是经常在程序外部使用python库的话,

为了确保python版本是兼容的,应用程序会为其相关的python版本定义一个若引用,类似这样:

1
2
3
4
# in maya's package.py
requires = [
"~python-2.7.3"
]

这里的示例表示,当环境中存在maya时,所有使用python的软件包都将使用与maya兼容的版本。

隐式软件包

这个翻译不知道对不对,原文为Implicit package
它是一个包请求列表,列表里的每个包会自动添加到每一个Rez请求中。
(例如当使用rez-env时,类似一个默认值的设定)

它们由rez配置implicit_packages设置,下面是默认值:

1
2
3
4
5
implicit_packages = [
"~platform=={system.platform}",
"~arch=={system.arch}",
"~os=={system.os}",
]

rez默认将当前系统的平台,架构,操作系统打包。
这确保了有任何对上述信息有依赖时,能够更好的进行匹配。
当进入一个环境时,可以看到输出信息会打印出这些implicit包。

解析依赖

Rez包含一个求解算法,算法接受一个程序请求列表,然后解析成一个满足程序包请求的最终列表。
例子:

image.png

这里有三个软件包:foo,bah和eek,其中foo和bah都对eek有依赖性。
比如软件包bah-4有个定义文件如下:

1
2
3
4
5
6
7
name = "bah"

version = "4"

requires = [
"eek-2.6"
]

而这个时候foo也会请求eek包,假设我们对foo包要求是“任何版本”,
这个时候解析返回的结果会是:(foo1.2,bah-4,eek2.6),Rez会提供不会导致冲突的最新版本

有时候你的请求无法实现,大致是因为请求(foo1.3,bah-4)导致的。
在这样的情况下解析会失败,Rez会告诉你有关的冲突。

环境解析

用户使用命令行工具rez-env解析并创建环境。
(也可以通过API完成,实际上rez中所有功能都可以在python中完成)
当你执行命令后,shell中的环境就被改变了,下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
]$ rez-env foo bah

You are now in a rez-configured environment.

resolved by ajohns@14jun01.methodstudios.com, on Wed Oct 22 12:44:00 2014,
using Rez v2.0.rc1.10

requested packages:
foo
bah

resolved packages:
eek-2.6 /packages/inhouse/eek/2.6
foo-1.2 /packages/inhouse/foo/1.2
bah-4 /packages/inhouse/bah/4

> ]$ █

输出的信息可以看到原始的请求和匹配的解析包。
注意>字符是一个提示,告诉你已经在rez解析的环境中。

小结

这里给一个新的(更接近生产环境需求的)示例,假设我们需要:

  • maya-2014.sp2
  • nuke-8.0v3
  • maya插件 mplugin 的三个版本
  • nuke插件 nplugin 的两个版本
  • 基础库lib的三个版本

下图显示了运行命令rez-env mplugin-1.3.0时,发生的情况。

image.png

如上图所示,Rez接受用户的请求,并解析依赖。

Rez Dependency Solver从软件存储库中读取软件包,以完成解析。

这个时候返回了一个最终软件包列表。

每个软件包命令是串联在一起的,rez会将它“打包”成一个目标Shell语言(图片中为bash)。

然后rez会创建一个sub-shell,并在环境中获取翻译后的命令代码,从而创建最终配置的环境。

软件包命令的执行顺序取决于软件包的依赖性以及请求软件包的顺序。