task icon indicating copy to clipboard operation
task copied to clipboard

Dynamic Variables only calculated once if "sh:" is identical

Open is-jonreeves opened this issue 4 years ago • 6 comments

  • Task version: 3.6
  • Operating System: Windows 10, Alpine Linux 3.13

It seems like Dynamic Variables that share the same verbatim sh: line will not get recomputed when run in their new context. For example if a global var is set to the current dir, but then a task with dir: ../ re-sets it, this value does not update for that task. If you make a slight tweak to the sh: command, it does work.

Example Taskfile showing the issue

version: '3'
silent: true

vars:
  PROJECT_ROOT:
    sh: echo $PWD

tasks:

  # Use Global Dynamic Var
  example1:
    cmds:
      - echo "Example 1"
      - echo "{{.PROJECT_ROOT}}"

  # Redefine Global Dynamic Var as Local Dynamic Var (with own dir context)
  example2:
    dir: ../
    vars:
      PROJECT_ROOT:
        sh: echo $PWD
    cmds:
      - echo "Example 2"
      - echo "{{.PROJECT_ROOT}}"

  # Create a new Local Dynamic Var (with own dir context)
  example3:
    dir: ../../
    vars:
      REPO_ROOT:
        sh: echo $PWD
    cmds:
      - echo "Example 3"
      - echo "{{.REPO_ROOT}}"

Expected:

Example 1
C:\Users\jon\Projects\taskfile-test
Example 2
C:\Users\jon\Projects
Example 3
C:\Users\jon

Actual:

Example 1
C:\Users\jon\Projects\taskfile-test
Example 2
C:\Users\jon\Projects\taskfile-test
Example 2
C:\Users\jon\Projects\taskfile-test

Workaround

If you tweak the sh: command to be unique each time its used, then it appears to force it to rerun correctly. So something like this will allow it to work:

sh: echo $PWD
sh: echo $PWD''
sh: echo $PWD''''  

Side-Note/Feature on Directories

I'll probably open a feature request for this, but the reason that I am jumping through the above hoops is that there doesn't seem to be an official "special variable" to get the Current Working Directory, which would be really handy. For commands that requires a Abs paths like Docker, obtaining these in a cross-platform manner can be annoyingly repetitive to mange. If there was a "special variable" with the current working directory and it was correctly affected by the dir: within each task, this would help a lot especially with the "slim-sprig" functions.

is-jonreeves avatar Jul 18 '21 18:07 is-jonreeves

I'm of the opinion that the second example should work, and that re-initializing a global var in the local scope should be something that is supported.

@andreynering would you agree that a global variable re-initialized as a local variable should be a supported feature? If so I can create a new, simpler issue that we can create a PR against.

@is-jonreeves I agree that some special variables would be desirable, as mentioned in issue #525.

weeping-somnambulist avatar Jul 28 '21 21:07 weeping-somnambulist

Hi @is-jonreeves, and thanks for opening these issues!

@SwitchedToGitlab's suggestions make sense, but may not be easy to implement.


Note to myself: Another way to fix this would be to allow cache: false setting on vars. This likely wouldn't be a good idea, though, as these vars could run many times without cache, more than once per task, given the current implementation. This would certainly be unexpected to users.

andreynering avatar Aug 01 '21 00:08 andreynering

At the very least, dynamic variable caching must take into account the working directory. We have two tasks with different working directories which both use realpath XXXX to resolve file paths. These are both cached to the same value so whichever one runs first sets it and the other one reads it, so one task will always end up with an incorrect value.

Porges avatar Sep 20 '21 21:09 Porges

See this commit for example problem/fix: https://github.com/Azure/azure-service-operator/pull/1742/commits/f83921dbe26080dae5715cfe8a9a6629e29cc1b9

Porges avatar Sep 20 '21 21:09 Porges

I kind of like the idea of an "uncachable" variable, because it would act kind of like a function.

Though the solution to this problem may be lazy variables discussed in V4. Basically a variable doesn't get evaluated (nor cached) until the first time it's actually used. Thus, you can define a variable as a global, and it won't even run until it's referenced elsewhere.

Though, this example does bring to light that with lazy variables, you may still want eager evaluation, such as in the example below, where you want to know the PWD of where the taskfile lives, thus, defining it as a global makes the most sense.

vars:
   PROJECT_DIR:
      sh: echo $PWD

In V4, I can look at supporting both eager & lazy functionality. I can also look into "uncachable" variables, which would likely not be a default behavior, but interesting none the less.

ghostsquad avatar Apr 29 '22 05:04 ghostsquad