How to make a task cacheable when the OutputFile path can be changed

Hi folks!

I have a task and I’d like to make it cacheable.

So there is an InputFile property and an OutputFile property in the task.
The problem is that I don’t know the OutputFile path until the task is completed.

To create the OutputFile I have to run an external application. It creates a file and returns the file path. The path is stable (there is a hash of the contents in the subdirectory name) but it is a private API and impossible to predict.
So the simple solution doesn’t work

@CacheableTask
class MyTask: DefaultTask() {
	@InputFile
	val x: project.objects.fileProperty()

	@OutputFile
	val y: project.objects.fileProperty()

	@TaskAction
	fun action() {
		// this is pseudo code, but it shows an idea
		// I get y path once an external app generates it
		y = callExternalApplication(x)
	}
}

I can’t set the “y” path during configuration, so the task is always out of date.
Another approach I invented

@CacheableTask
class MyTask: DefaultTask() {
	@InputFile
	val x: project.objects.fileProperty()

	@OutputFile
	val localPathCache: project.layout.buildDirectory.file("path.txt")

	@OutputFile
	val externalOutputFile = localPathCache.map {
        if (it.exists()) {
            val path = it.readLines().first()
            File(path)
        } else {
            File("doen-not-exist") // It's impossible to return null from provider 
        }
    }

	@TaskAction
	fun action() {
		val path = callExternalApplication(x)
		localPathCache.writeText(path)
	}
}

I write the path in an intermediate file. I suppose if the file does not exist or if the path from the file does not exist, task should run. But that doesn’t work either.
If I understand correctly, Gradle reads all properties Before the task is run, but not after. Next run Gradle thinks the externalOutputFile path has changed (it was “does-not-exist”) and runs the task again.

So the question is, is it possible to implement such a case?

Any advice is highly appreciated

As long as you do not get your task up-to-date, it can also not be cacheable.
Does the file really have to be where that external application puts it?
Otherwise, the solution is pretty simple.
Do make y configurable, run the external application to create the file at z, then rename / move the file to y.

Thanks for your help.

Unfortunately the external application expects the file in the same path. And it doesn’t have option ether input nor output path.

I thought about symlink. It may be a solution, but as I understand it won’t work on Windows.

Symlinks can work on windows, but with quite some hassle, unless you use WSL.
But why is it relevant where that external application expects the file?
Your task has an input and an output.
You give that external application the input and it produces the output.
But as I said, the task does not have to stop after calling that external application, but can simply move the file the external tool created to the place where the task output should be.