Rez中文文档06 Package Commands
Rez中文文档06 Package Commands
lingyun概述
程序包定义文件(package.py)通常定义命令的部分。
这是一个例子,用于确定如何配置环境和软件包的Python函数:
1 | def commands(): |
这是一个典型例子,程序包将其路径添加到PYTHONPATH,并将其工具添加到PATH。{root}
字符串代表软件包的安装目录。
配置rez环境后,解析列表中的每个软件包都将其命令部分解释并转换为shell代码。
(bash或其它,这取决于系统平台。)shell代码是源代码,用于配置环境。
在已配置的环境中,变量REZ_CONTEXT_FILE
指向此shell代码文件,
然后命令rez-context-interper
会对其进行打印输出。
在commands函数中使用的python API称为rex(rez执行语言)。
你可以使用此API执行一些常见操作,包括设置环境变量。
注意:如果需要导入任何python模块在命令部分中使用,则import语句必须在该函数中。
执行顺序
包的commands执行顺序取决于两个因素,请求包的顺序和包之间的依赖关系。
- 如果程序包B之前请求了程序包A,则A的命令在B之前解释执行
- 除非程序包A需要(取决于)程序包B,在这种情况下,程序包B将优先解释执行
比如一个名为”maya_anim_tool”的包,肉眼可见的它是一个maya插件,它依赖于maya。
因此,将优先解释执行maya的命令,这是因为maya插件可能取决于maya设置的某些环境变量。
maya会初始化MAYA_PLUG_IN_PATH变量,然后”maya_anim_tool”会添加到这里面。
一个例子:rez-env maya_anim_tool-1.3+ PyYAML-3.10 maya-2015
假设PyYAML依赖于python,而maya_anim_tool依赖于maya,则命令的执行顺序为:
- maya
- maya_anim_tool
- python
- PyYAML
添加环境变量
对于类PATH的环境变量,可以添加到此变量前面,或后面。
比如向后添加:env.PATH.append("{root}/bin")
不过,对于任何给定变量的第一个append/prepend操作实际上会覆盖该变量。
因为考虑到了”PYTHONPATH”在系统级别上已经配置了一些PATH变量。
例如,PyQt在系统变量的”PYTHONPATH”上,同时又使用rez-env设置了不同版本的PyQt,
那么在已配置版本的环境中导入它,仍然会不正确的导入系统版本。
Tips:
PATH比较特殊,它不是简单的覆盖,因为这样会丢失一些重要的系统路径,比如无法使用ls
或cd
等命令。
通常这种情况下,在解释完所有命令后,系统路径将附加回PATH。
rez将来的新特性可以为变量指定各种模式,例如一种模式会将原始(pre-rez)值附加回结果值。
支持的字符引用
可引用的对象字符
commands部分可用的任何对象都可以作为字符引用,该字符会传递给rex函数,例如:
appendenv("PATH", "{root}/bin")
在这里”{root}”将解释为root的值,root的值是软件包的安装路径(也可以使用”this.root”)。
它的代码和下述是同样的意思,只是下述的代码更冗长:
1 | import os.path |
通过env对象还支持下面这种写法:
env.FOO_LIC = "{this.root}/lic"
环境变量引用字符
支持语法是$FOO和${FOO}。
Literal函数
你可以使用literal
函数,来将对象或环境变量的特殊字符注释掉。比如:
env.TEST = literal("this {root} will not expand")
它还有个扩展功能是,类似格式化字符的用法,将字符和变量组合起来:
env.DESC = literal("the value of {root} is").expandable("{root}")
expandvars函数
字符引用通常只在将字符传递给rex函数或env对象的时候发生。
例如一个简单的语句”var = {root}/bin”,这里的”{root}”就不会被解释成安装包路径。
但是可以使用expandvars
函数来启用字符引用:
var = expandvars("{root}/bin")
预载和后置命令
我们可以为程序包设置pre_commands或post_commands。
执行顺序为:
- 所有软件包的pre_commands以标准顺序执行
- 然后执行所有包的commands
- 最后执行所有包的post_commands
预构建命令
在构建一个软件包的时候是不会执行commands的,原因是软件包不在其自身的构建环境中。
但是有时候需要在构建的时候运行命令,例如将一些环境变量传递到构建系统。
pre_build_commands
函数就可以实现。
预测试命令
在运行包测试的环境中执行一些额外的配置很有用。
可以定义pre_test_commands
函数来执行此操作。
一个例子
这是一个包定义的示例,其中的commands部分非常冗长:
1 | name = "foo" |
可使用的对象
commands函数中(包括pre_commands和post_commands)可以使用各种对象和函数。
例如,env是类似dict对象,表示目标环境中构造的所有环境变量。
以下是可用对象和功能:
alias(Function)
创建一个命令别名。
alias("nukex", "Nuke -x")
base(String)
this.base: 与this.root类似,但不包含变量的子路径(如果有的话)。
build(Dict-like object)
1 | if build.install: |
这个对象只能在”pre_build_commands”函数中使用。有以下字段:
- build.build_type:参数可以是”local”或”central”,表示发布软件包在本地或是中央存储库。
- build.install: 如果安装在进行中返回True,否则返回False。
- build.build_path:构建目录的路径(不是安装路径)。通常位于要构建软件包的./build子目录中的某个位置。
- build.install_path:安装目录的路径。注意即使没有进行安装也会进行设置。(不要检查这个变量来检测是否正在安装)。
building(Boolean)
1 | if building: |
如果正在进行构建(通常用rez-build工具完成),则此布尔变量为True,否则为False。
常见的用法是,一个包会使用这个判断来设置环境变量,这些变量只在构建过程中生效。
比如上述的例子。
command(Function)
command("rm -rf ~/.foo_plugin")
运行任意的shell命令。注意不能用这个函数来获取返回值,因为命令并没有运行。
只要在包被解释并转换为shell语言之后才会执行它们的命令。
如果有需要的话,尽可能在Python中执行简单的操作(例如文件操作等)。
它可以立即生效,且跨平台使用。如下:
1 | def commands(): |
comment(Function)
1 | if "nuke" in resolve: |
在转换后的shell脚本代码中创建注释行。当用户使用命令rez-context —interpret
或查看环境变量”REZ_CONTEXT_FILE”所引用的文件时,可以看到这个注释行。
defined(Function)
1 | if defined("REZ_MAYA_VERSION"): |
这个布尔函数将返回是否设置了这个环境变量。
env(Dict-like object)
1 | env.FOO_DEBUG = 1 |
env对象表示所配置的环境变量字典。需要注意的是,这和python的os.environ返回的字典不一样。
env只表示正在配置的环境,如果之前的程序通过env对象设置了变量,则只能在env中看到变量,
os.environ是看不到的,因为os.environ并不会随之更新。
env对象还提供以下功能:
env.append(Function)
env.PATH.append("{root}/bin")
将值附加到环境变量中。默认它使用os.pathsep分隔符,
但是也可以配置”env_var_separators”覆盖它。env.prepend(Function)
env.PYTHONPATH.prepend("{root}/python")
同上,只是将变量加到最前面。
ephemerals(Dict-like object)
1 | if "foo.cli" in ephemerals: |
代表已解析完成环境中的临时字典。字典里每一项都是一个字符串(例如fooc.li-1),使用get_range来测试intersects函数(一个布尔函数,如果给定对象的版本在给定版本范围内,则返回True),下面是一个用法示例:
1 | if intersects(ephemerals.get_range("foo.cli", "1"), "1"): |
error(Function)
1 | if "PyQt" in resolve: |
打印一个标准错误,只有打印作用,不会阻止环境构建(要阻止使用stop命令)。
getenv(Function)
1 | if getenv("REZ_MAYA_VERSION") == "2016.sp1": |
获取环境变量的值,如果变量不存在,触发”RexUndefinedVariableError”。
implicit(Dict-like object)
1 | if "platform" in implicits: |
类似于request对象(request表示程序包请求列表组成的字典),不同的是它仅包含由implicit_packages配置定义的包请求。
info(Function)
info("floob version is %s" % resolve.floob.version)
打印一个标准输出。
intersects(Function)
1 | if intersects(resolve.maya, "2019+"): |
一个布尔函数,如果给定对象的版本在给定的版本范围内,则返回True。
可查询的有效对象包括:
- 一个已解析的包,eg
resolve.maya
- 一个包请求,eg
request.foo
- 一个已解析包的版本,eg
resolve.maya.version
- 一个已解析的ephemeral,eg
ephemerals.foo
- 一个版本范围对象,eg
ephemerals.get_range('foo.cli', '1')
注意:不要这样做if intersects(ephemerals.get("foo.cli", "0"), "1"): ...
如果不存在”foo.cli”,这将把返回的默认值0与范围1进行比较,它会返回True。
在测试临时对象的交集时,请使用get_range:if intersects(ephemerals.get_range("foo.cli", "0"), "1"): ...
literal(Function)
将特殊字符注释掉(使其失效)。env.FOO = literal("this {root} will not expand")
也可以像这样将文字和可扩展字符链接起来:env.FOO = literal("the value of {root} is").expandable("{root}")
request(Dict-like object)
1 | if "maya" in request: |
表示包请求列表的字典,以包的名称为键,比如下面这条命令。
1 | ]$ rez-env maya-2015 maya_utils-1.2+<2 !corelib-1.4.4 |
会生成如下的对象:
1 | { |
使用get_range函数来测试intersects函数:
1 | if intersects(request.get_range("maya", "0"), "2019"): |
resolve(Dict-like object)
1 | if "maya" in resolve: |
表示已解析环境中的包列表字典。每个键为包的名称,值为包对象。
root(String)
this.root
包的安装目录,如果程序包包含变量,则此路径包含变量的子路径。
setenv(Function)
setenv("FOO_PLUGIN_PATH", "{root}/plugins")
将环境变量设置为给定的值。相当于env.FOO = "BAH"
source(Function)
source("{root}/scripts/init.sh")
执行一个shell脚本。类似于commands,此函数不会有返回值。
stop(Function)
stop("The value should be %s", expected_value)
引发异常并阻止继续解析。当检测到无法配置有效环境的错误时,使用它。
system(System object)
1 | if system.platform == "windows": |
该对象提供系统信息,比如当前平台,架构或操作系统。
查看这个文件可以获取更多信息:https://github.com/nerdvegas/rez/blob/master/src/rez/system.py
test(Dict-like object)
1 | if test.name == "unit": |
这个对象仅在”pre_test_commands”函数中生效。具有以下的字段:
- test.name:将要运行的测试名称。
this(Package object)
1 | import os.path |
表示当前包,下面是一些常用的命令:
- this.base:类似this.root,返回包路径,不包含子路径。
- this.name:包的名字,比如”houdini”。
- this.root:包的安装路径,包含子路径。
- this.version:返回版本对象,可以作为一个字符串使用,也可以访问版本中特定标识(如主要版本号等),演示代码:
env.FOO_MAJOR = this.version.major # or, this.version[0]
undefined(Function)
1 | if undefined("REZ_MAYA_VERSION"): |
一个布尔函数,环境变量如果没有被定义则返回True,与defined刚好相反。
unsetenv(Function)
unsetenv("FOO_LIC_SERVER")
删除指定的环境变量,如果没有这个环境变量,则该函数不执行任何操作。
version(Version object)
版本对象。可以见上述的this.version。