task icon indicating copy to clipboard operation
task copied to clipboard

`.task` directory generation should respect `dir` attribute

Open Muzosh opened this issue 1 month ago • 5 comments

Description

Problem

Including a taskfile which contains any task with generates: breaks the checksum check depending on from which taskfile the task was run.

Example

Consider following structure:

.
./docs
./docs/some-source-files/*.md
./docs/Taskfile.docs.yml
./Taskfile.main.yml

The Taskfile.docs.yml:

version: '3'

tasks:
  pdf:
    desc: "Compile source files to PDF"
    sources:
      - "./some-source-files/*.md"
    generates:
      - "Docs.pdf"
    cmds:
      -  <some command that generates Docs.pdf from source markdown files>
    silent: false

I want to make pdf task available from the root directory. Taskfile.main.yml:

version: '3'

includes:
  docs_generation:
    taskfile: "./docs/Taskfile.docs.yml"
    dir: "./docs"
    aliases: [dg]

tasks:
  some_other_tasks:

Problem reproduction

cd ./docs && task pdf produces a .task directory with a checksum name pdf in ./docs/.task/checksum/pdf

However, task dg:pdf generates .task directory in root directory, with different name: ./.task/checksum/docs_generation-pdf

Expectations

If I include a pdf task from docs generation in main taskfile, I explicitly set dir: "./docs" so that Task should be run from within that directory. I would expect the .task directory to be also created/checked from within that directory.

This also means that the docs generation will be run even if it's up-to-date, because some other user run it from different taskfile than me. (Yes, I want to commit the checksums because I also commit the generated PDF).

Tried solutions

Setting TASK_TEMP_DIR=./docs/.task task dg:pdf + adding label: pdf to the pdf task solves this. However, what if I want to have multiple inclusions, not only from docs folder, where the included task has generates:?

I would have to type separately TASK_TEMP_DIR=./where-target-taskfile-is-located/.task everytime based on which included task I'm about to run. I believe this is not intented.

Muzosh avatar Dec 09 '25 13:12 Muzosh

You might try this wrapping technique:

version: '3'

tasks:
  pdf:
    desc: "Compile source files to PDF"
    dir: '{{.TASKFILE_DIR}}'  # I think this is correct
    cmds:
      - task pdf_real

  pdf_real:
    silent: true
    sources:
      - "./some-source-files/*.md"
    generates:
      - Docs.pdf
    cmds:
      -  touch Docs.pdf

trulede avatar Dec 09 '25 17:12 trulede

Hmm, this indeed works and solves the issue.

But I don't quite understand it. The dir is specified for the pdf (my original pdf, not your new pdf) in the Taskfile.main.yml. Would you be able to explain the logic behind it? Is the behavior intended? Should it be like this?

Muzosh avatar Dec 09 '25 19:12 Muzosh

In your example, if I change - task pdf_real to - task: pdf_real, I can again replicate this and create two different .task/checksum based on where I run this task from.

Muzosh avatar Dec 09 '25 19:12 Muzosh

You want to the .task folder for that task to be in the same location, no matter how it is imported/called. One way to achieve that is to always run that particular task in a separate call to task. Task starts in that folder, creates the .task folder, runs the task, which does the conversion. Its exactly what you wanted.

The temp dir (.task) is always relative to the root taskfile. So with many different taskfile based projects importing the same taskfile, you cannot achieve what you want directly. Therefore a wrapper is the solution.

trulede avatar Dec 09 '25 20:12 trulede

Thanks for the explanation.

The temp dir (.task) is always relative to the root taskfile.

Is this intended feature though? From the docs, I can't find any other use case for .task folder other than checksum/timestamp checking. And having temp dir always relative to the root taskfile makes this checking inconsistent. Having a .task folder right next to the imported/included taskfile (the one that actually has the task with generates:) makes much more sense to me.

Muzosh avatar Dec 10 '25 08:12 Muzosh

Its a matter of perspective. You have a project (or sub-project) that you want to build from many many other projects. Task is used to build a project (singular). The imports mechanism is designed to bring other tasks, not taskfiles, into a project. This is a different thing than you are expecting.

But OK. Only a small problem.

I gave you one idea already, but I have another. Don't depend on Task to track the checksum of your file, rather, do it yourself! Write a task that generates the PDF, calculates its checksum, and stores that next to the PDF file (in another file). Next, add some commands before that in your task, to compare your PDF files checksum against the checksum stored in that additional file and then only generate the PDF if the checksums do not match.

That is what task is doing, so if you do that for your use case, then you have another solution.

I think your use case is valid, it makes sense to do that. So one of those ideas will work for you.

trulede avatar Dec 11 '25 20:12 trulede