kcl-lang / kcl-lang.io

KCL Website and Documentation Repo: https://kcl-lang.io
https://kcl-lang.github.io
Apache License 2.0
12 stars 33 forks source link

[FAQ] How do you merge two dictionaries and override values? #327

Closed reckless-huang closed 4 months ago

reckless-huang commented 5 months ago

kclcode

_image = option("image", help="镜像地址", required=True)
_app : str = option("app", help="应用名称", required=True)
_namespace : str = option("namespace", help="命名空间") or "default"
# https://github.com/kcl-lang/kcl-go/issues/271
# envs = option(key="envs",type="dict", help="环境变量")
_envs = option("envs",type="dict", help="环境变量")
_MQTT_BROKER_URL = option("MQTT_BROKER_URL", help="MQTT_BROKER_URL", required=False) or "tcp://1111"
_EDGEMANAGER__CLOUDBROKERADDR = option("__EDGEMANAGER__CLOUDBROKERADDR", help="__EDGEMANAGER__CLOUDBROKERADDR", required=False) or "tcp://1111"
_EDGEMANAGER__NODEID = option("__EDGEMANAGER__NODEID", help="__EDGEMANAGER__NODEID", required=False) or "tcp://1111"
_EDGEMANAGER__CACERTHTTPSERVER = option("__EDGEMANAGER__CACERTHTTPSERVER", help="__EDGEMANAGER__CACERTHTTPSERVER", required=False) or "tcp://1111"
_static_env_map = {
    "MQTT_BROKER_URL": _MQTT_BROKER_URL,
    "__EDGEMANAGER__CLOUDBROKERADDR": _EDGEMANAGER__CLOUDBROKERADDR,
    "__EDGEMANAGER__NODEID": _EDGEMANAGER__NODEID,
    "__EDGEMANAGER__CACERTHTTPSERVER": _EDGEMANAGER__CACERTHTTPSERVER

}
# _static_envs = [
#                             {
#                                 name = "MQTT_BROKER_URL"
#                                 value = _MQTT_BROKER_URL
#                             }
#                             {
#                                 name = "__EDGEMANAGER__CLOUDBROKERADDR"
#                                 value = _EDGEMANAGER__CLOUDBROKERADDR
#                             }
#                             {
#                                 name = "__EDGEMANAGER__NODEID"
#                                 value = _EDGEMANAGER__NODEID
#                             }
#                             {
#                                 name = "__EDGEMANAGER__CACERTHTTPSERVER"
#                                 value = _EDGEMANAGER__CACERTHTTPSERVER
#                             }
# ]
# print(envs)
# print(_app)
assert _envs != None , "envs is required"
if _envs:
    _dy_env = [{
        name: k
        value: v
    } for k,v in   _static_env_map | _envs]
else:
    _dy_env = []
{
    apiVersion = "apps/v1"
    kind = "Deployment"
    metadata = {
        name = _app
        namespace = _namespace
    }
    spec = {
        replicas = 1
        selector = {
            matchLabels = {
                app = _app
            }
        }
        template = {
            metadata = {
                labels = {
                    app = _app
                }
            }
            spec = {
                containers = [
                    {
                        name = _app
                        image = _image
                        # env = _static_envs +  _dy_env
                        env = _dy_env
                        ports = [
                            {
                                containerPort = 80
                            }
                        ]
                        volumeMounts = [
                            {
                                mountPath = "/data"
                                name = "data"
                            }
                        ]
                    }
                ]
                volumes = [
                    {
                        name = "data"
                        persistentVolumeClaim = {
                            claimName = _app
                        }
                    }
                ]
            }
        }
    }
}
if _envs:
    _b = [{name: k, value: _envs[k]} for k in _envs]

go code

    a, _ := json.Marshal(map[string]string{"aa": "bb","MQTT_BROKER_URL":"tcp://aaaaaaaaaaaa"})
    fmt.Println(kcl.MustRun("amd64.k", kcl.WithOptions("app=nginx", "image=aaa", fmt.Sprintf("envs=%s", string(a)))).GetRawYamlResult())

errors

43 |     } for k,v in   _static_env_map | _envs]
   |  conflicting values on the attribute 'MQTT_BROKER_URL' between :
    "tcp://1111"
and
    "tcp://aaaaaaaaaaaa"
with union path :
    MQTT_BROKER_URL
try operator '=' to override the attribute, like:
    {...} | {
            ...
            MQTT_BROKER_URL = "tcp://aaaaaaaaaaaa"
            ...
    }
Peefy commented 5 months ago

See the FAQ: https://www.kcl-lang.io/docs/user_docs/support/faq-kcl#37-how-to-modify-existing-configuration-blocks-in-kcl

The specific reason is that the envs input from external sources uses a merge operator, which checks for conflicts. If you want to completely overwrite it, you can use a new envs and use the overwrite operator e.g. need_to_merge_envs={k=v for k, v in envs} Note that I've used = here.

reckless-huang commented 5 months ago

magic

if _envs:
    _dy_env = [{
        name: k
        value: v
    } for k,v in   _static_env_map | {k=v for k,v in _envs}]
else:
    _dy_env = []