问题背景
在实际开发过程中会遇到多个产品,需要做不同定制的情况,如果不想维护多个特性分支,那么可以采用 options (选项开关/特性开关)做一个通用的处理方式。
对此有两种方式可供选择CMakeLists.txt和conanfile,由于不是全部组件都有CMakeLists.txt,本文将以conanfile方式,webui组件为例进行说明。
新增options开关
通过options进行选择,需要修改以下文件
- 1.service.json
options下新增board_name,举例为board_A,board_B,openUBMC
"options": {
#省略
"board_name":{
"option": [
"openUBMC",
"board_A",
"board_B"
],
"default": "openUBMC"
}
},
- 2.conanfile.py
注意
:
文件替换操作需要放到build当中,这样通过选择options,构建的组件包内容才会成功替换。
class WebUIConan(ConanBase):
# 省略
def _package(self)
if self.options.xxx:
src_file = os.path.join(self.source_folder, "file.lua")
dst_file = os.path.join(self.package_folder, "file.lua")
self.run(f"cp -f {src_file} {dst_file}")
else:
# copy b to xxx
def build(self):
ldap_enabled = self.options.ldap_enabled
energy_enabled = self.options.energy_enabled
if ldap_enabled == False:
build_ldap_enabled_configure()
if energy_enabled == False:
build_energy_enabled_configure()
self._package()
self.run(f"npm install")
self.run(f"npm run build")
优化修改
进行产品定制时肯定不止修改一个产品,一处文件,那么可以在原有基础上,增加文件映射的方式,简化替换文件操作,在使用的时候,只需要在对应的映射文件当中增添src和dst即可
定义存放映射文件路径为:组件名/oem/board_name/mappings.json
- 1.mappings.json
{
"files": [
{
"src": "源文件路径",
"dst": "目标文件路径"
}
]
}
- 2.conanfile.py
class WebUIConan(ConanBase):
# 省略
def build(self):
ldap_enabled = self.options.ldap_enabled
energy_enabled = self.options.energy_enabled
if ldap_enabled == False:
build_ldap_enabled_configure()
if energy_enabled == False:
build_energy_enabled_configure()
try:
# 默认openUBMC无需进行替换
if self.options.board_name != "openUBMC":
if not self.process_oem_files(self.options.board_name):
raise Exception(f"OEM 文件处理失败: {self.options.board_name}")
except Exception as e:
print(f"产品组件特性构建错误: {e}")
raise
self.run(f"npm install")
self.run(f"npm run build")
# 根据 board_name 加载配置文件并执行文件替换
def process_oem_files(self, board_name):
print(f"开始处理 {board_name} OEM 文件替换")
board_name_str = str(board_name)
config_path = Path("./oem") / board_name_str / "mappings.json"
if not config_path.exists():
raise Exception(f"未找到配置文件: {config_path}") # 如果配置文件不存在,抛出异常
try:
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
print(f"加载配置: {config_path}")
except Exception as e:
raise Exception(f"读取配置失败: {e}")
files = config.get("files", [])
if not files:
print("没有文件映射,跳过处理")
return True
success_count = 0
error_count = 0
for item in files:
src_file = item.get("src")
dst_file = item.get("dst")
if not src_file or not dst_file:
raise Exception(f"配置错误: src 或 dst 缺失")
src_path = Path(src_file)
dst_path = Path(dst_file)
if not src_path.exists():
raise Exception(f"源文件不存在: {src_path}")
if not dst_path.exists():
raise Exception(f"目标文件不存在: {dst_path}")
try:
# 执行文件替换操作
self.run(f"cp -f {src_path} {dst_path}")
print(f"复制成功: {src_path} -> {dst_path}")
success_count += 1
except Exception as e:
raise Exception(f"复制失败 {src_path} -> {dst_path}: {e}")
print(f"完成: {success_count} 成功, {error_count} 失败")
return True
CI建议修改
由于组件进行构建时只会进入到默认board_name,建议在CI中新增检查对应的检查
- 1.mappings.json中定义的src和dst文件路径存在
- 2.src和对应的dst文件名相同