Hooks¶
Conan Hooks 是一个旨在扩展 Conan 功能的特性,可以在包创建过程的不同阶段(例如预构建和后构建)执行某些正交操作,如一些质量检查。
Hook 结构¶
Hook 是一个 Python 函数,它将在 Conan 工作流的特定点执行,以自定义客户端行为,而无需修改客户端源代码或 Recipe。
这是一个简单的 Hook 示例
from conan.tools.files import load
def pre_export(conanfile):
for field in ["url", "license", "description"]:
field_value = getattr(conanfile, field, None)
if not field_value:
conanfile.output.error(f"[REQUIRED ATTRIBUTES] Conanfile doesn't have '{field}'.
It is recommended to add it as attribute.")
此 Hook 在 Recipe 被导出之前检查 Recipe 的内容。基本上,pre_export() 函数会检查 conanfile 对象的属性,看是否存在 URL、许可证和描述,如果缺少,则通过 conanfile.output 向用户发出警告。这是在 Recipe 被导出到本地缓存 **之前** 完成的。
可以执行任何类型的 Python 脚本。您可以创建全局函数并在不同的 Hook 函数中调用它们,从相对模块导入,并发出警告、错误甚至引发异常来中止 Conan 客户端的执行。
从模块导入¶
Hook 接口应始终放在一个 Python 文件中,Hook 的名称以 *hook_* 开头,并以 *.py* 为扩展名。它还应存储在 *<conan_home>/extensions/hooks* 文件夹中。但是,如果您已在系统中安装了它们,或者它们已随 Conan 一起安装,则可以使用导入模块的功能。
import requests
from conan.tools.files import replace_in_file
def post_package(conanfile):
if not os.path.isdir(os.path.join(conanfile.package_folder, "licenses")):
response = requests.get('https://api.github.com/repos/company/repository/contents/LICENSE')
您也可以从相对模块导入功能
hooks
├── custom_module
│ ├── custom.py
│ └── __init__.py
└── hook_printer.py
在我的 *custom_module* 的 *custom.py* 文件中有
def my_printer(conanfile):
conanfile.output.info("my_printer(): CUSTOM MODULE")
并且可以在 Hook 中像常规 Python 一样导入模块来使用它。
from custom_module.custom import my_printer
def pre_export(conanfile):
my_printer(conanfile)
Hook 接口¶
在这里,您可以看到一个包含所有可用 Hook 函数的完整示例
def pre_export(conanfile):
conanfile.output.info("Running before to execute export() method.")
def post_export(conanfile):
conanfile.output.info("Running after of executing export() method.")
def pre_validate(conanfile):
conanfile.output.info("Running before executing the validate() method.")
def post_validate(conanfile):
conanfile.output.info("Running after executing the validate() method.")
def pre_source(conanfile):
conanfile.output.info("Running before to execute source() method.")
def post_source(conanfile):
conanfile.output.info("Running after of executing source() method.")
def pre_generate(conanfile):
conanfile.output.info("Running before to execute generate() method.")
def post_generate(conanfile):
conanfile.output.info("Running after of executing generate() method.")
def pre_build(conanfile):
conanfile.output.info("Running before to execute build() method.")
def post_build(conanfile):
conanfile.output.info("Running after of executing build() method.")
def post_build_fail(conanfile):
conanfile.output.info("Running after failed execution of build() method.")
def pre_package(conanfile):
conanfile.output.info("Running before to execute package() method.")
def post_package(conanfile):
conanfile.output.info("Running after of executing package() method.")
def pre_package_info(conanfile):
conanfile.output.info("Running before to execute package_info() method.")
def post_package_info(conanfile):
conanfile.output.info("Running after of executing package_info() method.")
# Note that pre_package_id() hook doesn't exist yet, so far there hasn't been
# a use case
def post_package_id(conanfile):
conanfile.output.info("Running after executing package_id() method.")
Hook 的函数旨在对其执行进行自我描述。例如,pre_package() 函数在 Recipe 的 package() 方法执行之前被调用。
所有 Hook 方法都只填充同一个对象
conanfile:这是一个从接收 Conan 命令的 Recipe 加载的常规
ConanFile对象。它具有常规属性和动态对象,例如build_folder、package_folder、output、dependencies、options等。
存储、激活和共享¶
Hooks 是存储在 *<conan_home>/extensions/hooks* 文件夹下的 Python 文件,**它们的文件名应以 hook_ 开头,并以 .py 作为扩展名**。
一旦 Hook 文件存储在 Hook 文件夹中,Hook 就会自动激活。如果存储在子文件夹中,也会自动工作。
要禁用 Hook,应将其文件从 Hook 文件夹中删除。没有可以禁用但仍将文件存储在 Hooks 文件夹中的配置。
官方 Hook¶
在 Conan hooks GitHub 的独立存储库中,有一些官方维护的 Hooks,但它们大多仅与 Conan 1.x 兼容,所以请首先检查 README 以获取关于哪些 Hooks 与 Conan v2 兼容的信息。