我正在尝试构建一个依赖于非常动态配置的软件(或者#34;规则集",真的)。我试图用伪代码捕获它:
"""
---
config:
item1:
thething: ${stages.current.variables.item1}
stages:
dev:
variables:
item1: stuff
prod:
variables:
item1: stuf2
"""
config_obj = yaml.load(config)
current_stage = 'dev'
#Insert artificial "current stage" to allow var matching
stages['current'] = stages[current_stage]
updated_config_obj = replace_vars(config_obj)
目标是让updated_config_obj
将所有变量类型替换为实际值,因此对于此示例,它应将${stages.current.variables.item1}
替换为stuff
。通过将当前阶段中的任何内容复制到同一OrderedDict中的current
项中,可以轻松解决current
部分,但我仍然对如何实际执行替换感到困惑。配置yaml可能非常大,完全依赖于插件系统,因此必须是动态的。
现在我正在看着"行走"整个对象,检查每个"叶子上是否存在$
" (表示变量)并对当前对象执行查找备份以解决"解决"变量,但不知何故,似乎过于复杂。另一种选择是(我猜)你可以在#34;配置字符串"上使用解析对象作为查找。当然可行,但它感觉有点脏。
我觉得应该有一个更优雅的解决方案,只能在解析的对象上完成(不与字符串交互),但它逃脱了我。
任何指示赞赏!
答案 0 :(得分:0)
首先,我的两分钱:尽量避免在配置文件中使用任何形式的插值。这会创建另一层依赖项 - 程序的一个依赖项(配置文件)和配置文件的另一个依赖项。
目前它是一个灵活的解决方案,但考虑到未来五年,一些低级开发人员可能会盯着${stages.current.variables.item1}
一个月试图弄清楚这是什么,而不是理解这是隐含的映射到stages.dev
。然后更糟糕的是,一些其他开发人员出现了,并且看到插值的闸门已经打开,他们开始使用{{stages_dev}}
,意味着某些值应该从系统的环境变量中插入。然后其他一些开发人员开始使用他们自己的约定,如{{!stagesdev!}}
,这意味着该值使用自己的自定义运行时插值,在一些不起眼的下游后巷中调用。
然后聘请了一些顾问对整件事进行逆向工程,现在他们正在意大利海上航行。
如果您仍想这样做,我建议打开/解析配置文件到字典中(大概使用yaml.load()
),然后逐行遍历整个事物,使用正则表达式查找\$\{(.*)\}
的实例。
对于每个捕获的组,创建一个有序列表,如:
# ["stages", "current", "variables", item1"]
yaml_references = ".".split("stages.current.variables.item1")
然后,您可以执行以下操作:
yaml_config_dict = "" # the parsed configuration file
interpolated_reference = None
for y in yaml_references:
interpolated_reference = yaml_config_dict[y]
i = interpolated_reference[0]
现在i
应该表示在.yaml文件的上下文中指向的任何${stages.current.variables.item1}
,您应该能够进行字符串替换。