More complex inheritance in YAML?

后端 未结 3 1954
南方客
南方客 2021-01-31 02:00

YAML has inheritance. The most clear example I have ever seen is here: http://blog.101ideas.cz/posts/dry-your-yaml-files.html

I need something more complex: I need to ov

相关标签:
3条回答
  • 2021-01-31 02:16

    How about this? Use multiple anchors.

    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
    

    It's just a little extra work, and slightly harder to read than if what you wanted were built into YAML as you suggested (I thought it would work that way too). But overall not bad.

    0 讨论(0)
  • 2021-01-31 02:18

    Unfortunately, you can't get the kind of "inheritance" you want to achieve because YAML's "inheritance" is more like a form of "merging hashes".

    Expanding out your configuration at the point you use the *default alias, you have:

    foo_database:
      server:
        ip: 192.168.1.5
        port: 2000
      db_name: test
      user: 
        name: root
        password: root
    

    If you use hashes with the same keys afterwards, they will completely overwrite the hashes declared earlier, leaving you with (excuse the formatting):

    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
    

    So, in your case, it would seem that since the config is not exactly the same, DRYing up your configuration using anchors and aliases probably isn't the right approach.

    More references on this issue below:

    • Rake, YAML and Inherited Build Configuration
    • Merging hashes in yaml conf files

    Edit

    If you really wanted to, I think you could reconfigure your YAML as below to get exactly what you want, but in your case, I would say the extra obfuscation isn't worth it:

    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
    
    0 讨论(0)
  • 2021-01-31 02:20

    For this sort of problems, I have created a tool: jq-front. By using yq + jq-front, you can achieve it by slightly modifying your input.

    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
    

    And you can process this file by a following command line.

    $ yq . -j in.yaml | jq-front  | yq . -y
    

    And you will get following output that you wanted.

    foo_database:
      server:
        ip: 192.168.1.5
        port: 2001
      db_name: foo
      user:
        name: root
        password: foo_root
    

    NOTE: jq-front is very slow. On my machine the command took 2.5s, which did not matter to me too much since system configuration can be read once and only the converted file is used by the rest of my program.

    NOTE: If you use docker + bash, it's lot easier to install jq-front by docker. You only need to add following function to your .bashrc or a file that is sourced by it.

    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}" "${@}"
    }
    
    0 讨论(0)
提交回复
热议问题