upcmd / up

UP - Ultimate Provisioner CLI
https://upcmd.netlify.app/
MIT License
50 stars 4 forks source link

Pure local vars #18

Closed ppiccolo closed 4 years ago

ppiccolo commented 4 years ago

Hi,

if I use pure flag for local variables, other variables are not taken into account, in my opinion will be better if variable that are external to the callee keep their original value.

Bye

stephencheng commented 4 years ago

based on the doco:

Sometimes, you want all the local vars to be pure and entired isolated in its own context, then you can setup a flag - pure to protect the local vars not to be impacted by the merging process

In this case, the local vars and its sub call stack's var stack will be all protected because the sub stack will be an extention of this func call

The design is to cut off the chain of variables casting downwards only.

Normally:

(scope d|vars) -> (global d|vars) -> (local d|vars) --call--> (local d|vars)

With pure:

(scope d|vars) -> (global d|vars) --XX-- (local d|vars) --call--> (local d|vars), so it turns to:

(local d|vars) --call--> (local d|vars)

I am not sure what your intension is, I do not quite follow what you said: the external vars to the called should keep original value, do you mean not to apply the overriding process?

If so, do you have use case for this?

PS. please update to use latest version

ppiccolo commented 4 years ago

Normally:

(scope d|vars) -> (global d|vars) -> (local d|vars) --call--> (local d|vars)

With pure:

(scope d|vars) -> (global d|vars) --XX-- (local d|vars) --call--> (local d|vars), so it turns to:

(local d|vars) --call--> (local d|vars)

Ok the example clarify the actual implementation.

Taking as example the following (modified) showcase :

vars:
  a: aaa
  b: bbb
  c: ccc
tasks:
  - name: task
    desc: mock up test to test module.template rendering
    task:
      - func: cmd
        vars:
          b: bbb
          d: ddd
        flags:
          - pure
        do:
          - name: inspect
            desc: the vars in caller after invoking module task
            cmd:
              - exec_vars
              - exec_base_vars
          - name: assert
            cmd:
              #### Access to global variable a cause assertion failed because a is not defined              
              - '{{eq .a  "aaa"}}' 
              - '{{eq .b  "bbb"}}'
              - '{{eq .d  "ddd"}}'
      - func: call
        vars:
          e: first_level_eee
          f: first_level_fff
        flags:
          - pure
        do: substack
  - name: substack
    task:
      - func: cmd
        vars:
          f: fff
          g: ggg
          h: hhh
        do:
          - name: inspect
            desc: the vars in caller after invoking module task
            cmd:
              - exec_vars
              - exec_base_vars

Basically I like to access the globally defined a variable, and in case of a is defined in the pure local var context then only in this case override with the local value.

You can think as a default variable value to be able to call the task as standalone block

Bye

stephencheng commented 4 years ago

I understand technically what you want, I had the same consideration in the original design. However, this was ruled out after some careful thoughts.

I tried to make the tool generic and support the essential way for tooling and composability.

Let's look at all possible coverage of the vars handling

  1. leave level - we use local vars and pure
  2. top entry level - it inherits all upstream vars
  3. middle layer - since it is called, parameters (same names) are overridden from caller, which make sense

It seems that you don't want the caller to callee task to override the vars and you would like a way to behave like the item2, to inherit rather than override. My original thought to tackle this problem is to just use var naming pattern to solve it. So, you don't have to use pure in this case, you just need to use different names of vars

I believe in the example, if you remove pure, then you will get all the values of a, b,c and d. In the callee, you just need to use different names

Not sure if I answer your, but feel free to list the pain and problem, more detailed example, or biz case will all help.

stephencheng commented 4 years ago

@ppiccolo how do you go with it?

Just FYI that I have come out of some guidance of organizing directory structure and files, also shows what the better way is for CI/CD pipeline integration, maybe it's useful for your current terrorform work

Ref to: https://github.com/upcmd/up/tree/master/examples/0002/04

Or go step by step: https://github.com/upcmd/up/tree/master/examples/0002

ppiccolo commented 4 years ago

@stephencheng I've found an easy workaround decoupling the implementation from the caller.

I' understand your point,it's just a matter of knowing the way to go 😄

I'll take a look at your example.

Thank you 🙏