YAML有继承权。我见过的最明显的例子是:http://blog.101ideas.cz/posts/dry-your-yaml-files.html
我需要更复杂的东西:我需要覆盖对象的对象的属性。这是一个例子:
database: &default
server:
ip: 192.168.1.5
port: 2000
db_name: test
user:
name: root
password: root
# database foo differs from default by only its port and user password
foo_database:
<<: *default
server:
port: 2001
db_name: foo
user:
password: foo_root
我想得到这个结果:
foo_database.server.ip -> 192.168.1.5
foo_database.server.port -> 2001
foo_database.db_name -> foo
foo_database.user.name -> root
foo_database.user.password -> foo_root
但如果你这样声明,你会得到这些属性不正确(根据预期值):
foo_database.server.ip -> will be None
foo_database.user.name -> will be None
因为新的“server”对象只有“port”属性,它会覆盖整个旧的“server”对象。
如何获得我想要实现的继承?
答案 0 :(得分:31)
不幸的是,你不能得到你想要实现的那种“继承”,因为YAML的“继承”更像是一种“合并哈希”。
在您使用*default
别名时扩展您的配置,您有:
foo_database:
server:
ip: 192.168.1.5
port: 2000
db_name: test
user:
name: root
password: root
如果你之后使用具有相同键的哈希,它们将完全覆盖之前声明的哈希值,留下你(原谅格式化):
foo_database:
<击> 撞击>
<击> server:
ip: 192.168.1.5
port: 2000
db_name: test
user:
name: root
password: root
击> <击> 撞击>
server:
port: 2001
db_name: foo
user:
password: foo_root
因此,在您的情况下,似乎由于配置不是完全相同,使用锚点和别名来干扰您的配置可能不是正确的方法。
以下有关此问题的更多参考资料:
如果您真的想,我认为您可以按照以下方式重新配置您的YAML以获得您想要的内容,但在您的情况下,我会说额外的混淆是不值得的:
server_defaults: &server_defaults
ip: 192.168.1.5
port: 2000
user_defaults: &user_defaults
name: root
password: root
database: &default
server:
<<: *server_defaults
db_name: test
user:
<<: *user_defaults
foo_database:
<<: *default
server:
<<: *server_defaults
port: 2001
db_name: foo
user:
<<: *user_defaults
password: foo_root
答案 1 :(得分:9)
这个怎么样?使用多个锚点。
database: &default
server: &server
ip: 192.168.1.5
port: 2000
db_name: test
user: &user
name: root
password: root
foo_database:
<<: *default
server:
<< : *server
port: 2001
db_name: foo
user:
<< : *user
password: foo_root
这只是一个额外的工作,并且比你想要的内容更难以阅读,如你所建议的那样(我认为它也可以这样工作)。但总体来说还不错。
答案 2 :(得分:1)
针对此类问题,我创建了一个工具:jq-front。 通过使用yq + jq-front,可以通过稍微修改输入来实现。
in.yaml:
$local:
database_default:
server:
ip: 192.168.1.5
port: 2000
db_name: test
user:
name: root
password: root
# database foo differs from default by only its port and user password
foo_database:
$extends: [ database_default ]
server:
port: 2001
db_name: foo
user:
password: foo_root
您可以通过以下命令行处理此文件。
$ yq . -j in.yaml | jq-front | yq . -y
然后您将得到想要的输出。
foo_database:
server:
ip: 192.168.1.5
port: 2001
db_name: foo
user:
name: root
password: foo_root
注意:jq-front非常慢。在我的机器上,该命令花费了2.5秒,这对我来说并没有太大关系,因为系统配置可以读取一次,并且程序的其余部分仅使用转换后的文件。
注意:如果使用docker + bash,则通过docker安装jq-front会容易得多。您只需要将以下功能添加到.bashrc
或由其来源的文件中。
function jq-front() {
docker run --rm -i \
-v /:/var/lib/jf \
-e JF_PATH_BASE="/var/lib/jf" \
-e JF_PATH="${JF_PATH}" \
-e JF_DEBUG=${JF_DEBUG:-disabled} \
-e JF_CWD="$(pwd)" \
dakusui/jq-front:"${JF_DOCKER_TAG:-latest}" "${@}"
}