go-task / task

A task runner / simpler Make alternative written in Go
https://taskfile.dev
MIT License
11.01k stars 584 forks source link

Same task dependency from multiple tasks run repeatedly instead of once #812

Closed renatoathaydes closed 2 years ago

renatoathaydes commented 2 years ago

Darwin Renatos-Air 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:22 PDT 2022; root:xnu-8020.121.3~4/RELEASE_X86_64 x86_64

Example Taskfile showing the issue

version: '3'

tasks:
  foo: echo "foo"

  bar:
    deps: [ foo ]
    cmds:
      - echo "bar"

  zort:
    deps: [ foo ]
    cmds:
      - echo "zort"

Result:

▶ task bar zort
task: [foo] echo "foo"
foo
task: [bar] echo "bar"
bar
task: [foo] echo "foo"
foo
task: [zort] echo "zort"
zort

Expected result:

▶ task bar zort
task: [foo] echo "foo"
foo
task: [bar] echo "bar"
bar
task: [zort] echo "zort"
zort

Task managers should generally create a graph of tasks without duplicates.

If bar and zort both depend on foo, then the task order is simply:

  foo ->  bar
              zort

i.e. bar and zort both run after foo is executed, but may run in parallel. Running foo twice is almost certainly redundant, specially in the context of a build.

Adding sources to foo causes the second execution to be skipped, but in slightly more complex scenarios, the task seems to be executed multiple times.

Example from my real build output:

task: [compile] javac --release 11 ...
task: [compile] javac --release 11 ...
task: [compile] javac --release 11 ...
task: [jar] jar -c -f ...
task: [jar] jar -c -f ...
task: [jar] jar -c -f ...
task: [install-junit] java -jar ...
task: [install-test-libs] java -jar ...

The compile and jar tasks appear to have run 3 times each.

In the next execution, the tasks are skipped, showing that my build has appropriate sources declarations to avoid that:

task: Task "compile" is up to date
task: Task "compile" is up to date
task: Task "compile" is up to date
task: Task "jar" is up to date
task: Task "jar" is up to date
task: [install-test-libs] java -jar ...
task: Task "jar" is up to date

But notice that task still prints the up-to-date message multiple times.

In summary: it would be ideal to compute a single task graph without task duplication before running anything, but unfortunately that doesn't seem to be the case, currently.

postlund commented 2 years ago

Set run: once (https://taskfile.dev/api/#task) for foo and it will work that way.

renatoathaydes commented 2 years ago

Isn't run: once supposed to make it run once across multiple task invocations? If not, how do you do that instead?

renatoathaydes commented 2 years ago

What's the purpose of having tasks run multiple times by default? I have not seen any other task manager that does that.

postlund commented 2 years ago

Using run: once ensure the task is only run once no matter how many other tasks that depends on it. For me personally I prefer current default value. It is very common to pass variables to a task, which alter the task behavior, thus making multiple calls to the same task a valid case. A simple example would be a generic build task, accepting BUILD_PATH as an input to determine what to build. "Leaf-tasks" would then be added for each application or library depending on this task. Here I definitely want current default behavior of always running the task for each depending task.

renatoathaydes commented 2 years ago

I see your point. You see tasks more like functions: can invoked with different arguments, at any time. That's at odds with my internal model of what tasks should be (a simple graph). That's fine, I just need to adjust my mental model to use Task properly.

Given your philosophy of what tasks are, I believe there's no need to improve anything, so I am closing the ticket.

Thanks.

andreynering commented 2 years ago

And just to clarify, along with run: always and run: once there's also run: when_changed to only run when something in the task changed.

andreynering commented 2 years ago

Also, run can be set on the root of the Taskfile if you want this behavior for all tasks.

renatoathaydes commented 2 years ago

Also, run can be set on the root of the Taskfile if you want this behavior for all tasks.

Ah thanks! I was adding run: once to every single task :).