probe exisitence of path

When you render a template value based on a path of the var in the register, sometimes you will get as that element does not exist yet. This will appear as a warning error and ignored. However it is critial if this value will be used in workflow condition, then this might cause problem. So it is better to know if this element exist before accessing

Demo

source

Main task yaml file
    vars:
      a: aaa
      b: bbb
      sydney_grammar:
        address: sydney
    tasks:
    - name: task
      task:
      - func: cmd
        desc: |
          access a non-exist var will not cause error or panic while you render it
        do:
        - name: print
          cmd: '{{.c}}'
      - func: cmd
        desc: |
          however if you access a non exist child element, then it will result in a warning error
        do:
        - name: print
          cmd: '{{.b.not_exist}}'
      - func: cmd
        do:
        - name: query
          desc: |
            if the sub element does not exist, eg school_name does not exit, then the query result will give the result of the closest element result, in this caes the parent value "aaa" will be return
          cmd:
            path: a.school_name
            reg: myschool
        - name: query
          cmd:
            path: sydney_grammar.address
            reg: school_address
        - name: pathExisted
          cmd:
            path: sydney_grammar.address
            reg: address_existed
        - name: pathExisted
          desc: |
            the state will be rendered as <no value>, this will be treated as not exist
          cmd:
            path: sydney_grammar.state
            reg: state_existed
        - name: pathExisted
          cmd:
            path: b.not_exist
            reg: varb_sub_element_existed
        - name: print
          cmd: |
            sydney_grammar.address exist: {{.address_existed}}
            sydney_grammar.state exist: {{.state_existed}}
            varb_sub_element_existed exist: {{.varb_sub_element_existed}}
      - func: cmd
        desc: test pathExisted in templating
        do:
        - name: print
          cmd: |
            sydney_grammar.address exist: {{ pathExisted "sydney_grammar.address" }}
            sydney_grammar.state exist: {{ pathExisted "sydney_grammar.state"}}
            varb_sub_element_existed exist: {{ pathExisted "b.not_exist"}}
            {{ if pathExisted "b.not_exist"}}
            I am happy
            {{ else }}
            I am sad
            {{ end }}
      - func: cmd
        do:
        - name: inspect
          cmd:
          - exec_vars
        - name: assert
          cmd:
          - '{{pathExisted "sydney_grammar.address" }}'
    
Main log file
    loading [Config]:  ./tests/functests/upconfig.yml
    Main config:
                 Version -> 1.0.0
                  RefDir -> ./tests/functests
                 WorkDir -> cwd
              AbsWorkDir -> /up_project/up
                TaskFile -> c0154
                 Verbose -> vvv
              ModuleName -> self
               ShellType -> /bin/sh
           MaxCallLayers -> 8
                 Timeout -> 3600000
     MaxModuelCallLayers -> 256
               EntryTask -> task
      ModRepoUsernameRef -> 
      ModRepoPasswordRef -> 
    work dir: /up_project/up
    -exec task: task
    loading [Task]:  ./tests/functests/c0154
    module: [self], instance id: [dev], exec profile: []
    profile -  envVars:
    
    (*core.Cache)({
    })
    
    Task1: [task ==> task:  ]
    -Step1: [
    access a non-exist var will not cause error or panic while you render it
    ]
    self: final context exec vars:
    
    (*core.Cache)({
      "a": "aaa",
      "b": "bbb",
      "up_runtime_task_layer_number": 0,
      "sydney_grammar": {
        "address": "sydney"
      }
    })
    
    ~SubStep1: [print:  ]
    None
    -Step2: [
    however if you access a non exist child element, then it will result in a warning error
    ]
    self: final context exec vars:
    
    (*core.Cache)({
      "sydney_grammar": {
        "address": "sydney"
      },
      "a": "aaa",
      "b": "bbb",
      "up_runtime_task_layer_number": 0
    })
    
    ~SubStep1: [print:  ]
          template rendering -> template: .:1:4: executing "." at <.b.not_exist>: can't evaluate field not_exist in type interface {}
    WARN:
        1:{{.b.not_exist}}
    
    trouble shooting tips:
    <incompatible types for comparison>: the variable might not be registered, use -v vvv to see the cache, or use inspect cmd to debug
    
    
    -Step3:
    self: final context exec vars:
    
    (*core.Cache)({
      "sydney_grammar": {
        "address": "sydney"
      },
      "a": "aaa",
      "b": "bbb",
      "up_runtime_task_layer_number": 0
    })
    
    ~SubStep1: [query: if the sub element does not exist, eg school_name does not exit, then the query result will give the result of the closest element result, in this caes the parent value "aaa" will be return
     ]
    ~SubStep2: [query:  ]
    ~SubStep3: [pathExisted:  ]
    ~SubStep4: [pathExisted: the state will be rendered as <no value>, this will be treated as not exist
     ]
    ~SubStep5: [pathExisted:  ]
          element validating problem -> template: validator:1:4: executing "validator" at <.b.not_exist>: can't evaluate field not_exist in type interface {}
    WARN:
        1:{{.b.not_exist}}
    
    ~SubStep6: [print:  ]
    sydney_grammar.address exist: true
    sydney_grammar.state exist: false
    varb_sub_element_existed exist: false
    
    -Step4: [: test pathExisted in templating ]
    self: final context exec vars:
    
    (*core.Cache)({
      "sydney_grammar": {
        "address": "sydney"
      },
      "b": "bbb",
      "a": "aaa",
      "myschool": (*string)("aaa"),
      "school_address": (*string)("sydney"),
      "state_existed": false,
      "varb_sub_element_existed": false,
      "address_existed": true,
      "up_runtime_task_layer_number": 0
    })
    
    ~SubStep1: [print:  ]
          element validating problem -> template: validator:1:4: executing "validator" at <.b.not_exist>: can't evaluate field not_exist in type interface {}
    WARN:
        1:{{.b.not_exist}}
    
          element validating problem -> template: validator:1:4: executing "validator" at <.b.not_exist>: can't evaluate field not_exist in type interface {}
    WARN:
        1:{{.b.not_exist}}
    
    sydney_grammar.address exist: true
    sydney_grammar.state exist: false
    varb_sub_element_existed exist: false
    
    I am sad
    
    
    -Step5:
    self: final context exec vars:
    
    (*core.Cache)({
      "b": "bbb",
      "up_runtime_task_layer_number": 0,
      "state_existed": false,
      "myschool": (*string)("aaa"),
      "varb_sub_element_existed": false,
      "sydney_grammar": {
        "address": "sydney"
      },
      "a": "aaa",
      "school_address": (*string)("sydney"),
      "address_existed": true
    })
    
    ~SubStep1: [inspect:  ]
     1: inspect[exec_vars]
    (*core.Cache)({
      "myschool": (*string)("aaa"),
      "state_existed": false,
      "varb_sub_element_existed": false,
      "sydney_grammar": {
        "address": "sydney"
      },
      "a": "aaa",
      "b": "bbb",
      "up_runtime_task_layer_number": 0,
      "school_address": (*string)("sydney"),
      "address_existed": true
    })
    
    ~SubStep2: [assert:  ]
     1 ASSERT OK:     [{{pathExisted "sydney_grammar.address" }}]
    
Logs with different verbose level
Raw logs with different verbose level

Explain

Below shows how to use cmd pathExisted to get a boolean result and saved to a register value, then you can use it in your workflow to decide to go ahead to access the value of the var