What's the proper way to access resource outputs o...
# community-support
z
What's the proper way to access resource outputs of the
KspTask
Gradle task in a consumer task? I'm seeing:
Copy code
kspTask.outputs.files
return an empty
FileCollection
. Even though
build/generated/ksp/test/resources
is non-empty. If I re-execute the task (and Gradle does another configuration phase pass),
kspTask.outputs.files
is correctly non-empty and this works as expected.
v
If that task (cannot find the class
KspTask
anywhere) for example has an
@OutputDirectory
property, the actual output files can hardly be known before the task executed. "works as expected" is most probably also not correct, as you most probably get the files of the last ran and not the files that will be there after the next run.
💯 1
z
it’s this task
interface KspTask
implemented by `KspTaskJvm`: https://github.com/google/ksp/blob/d98bc9c3f8b8b14f3d62543d64707a49f8514c73/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KotlinFactories.kt#L184-L206 note: I’m referring to
kspTask.outputs.files
being empty when it is input to a downstream
Task
, such as:
Copy code
abstract class ListFilesTask : DefaultTask() {
  @get:InputFiles
  abstract val input: ConfigurableFileCollection

  // ..

}
I think this might be an issue with the configuration cache snapshotting some input at configuration time, bc when I run with
—no-configuration-cache
it seems to work on our CI server (our CI server is ephemeral and every build is a completely clean build, though it leverages a remote build cache)
one workaround I can think of is to create my own
objects.fileCollection()
and have it
.builtBy(kspTask)
- but I’m not sure why
kspTask.outputs
doesn’t work
v
why do you actually use
outputs.files
? Just give the task itself to the downstream task
iirc then CC should also be aware and not prematurely calculate the value
outputs.files
probably does not carry the task dependency
z
just give the task itself to the downstream task
what do you mean? My downstream task has a:
Copy code
@get:InputFiles
abstract val yamlFilesToMerge: SetProperty<FileSystemLocation>
as input
outputs.files
probably does not carry the task dependency
it does with:
Copy code
task.outputs
  .files
  .asFileTree
  .filter { it.isYamlFile() }
  .elements
which returns a
Provider<Set<FileSystemLocation>>
v
What does
it.isYamlFile()
do?
z
just a
file.endsWith(".yaml")
check. But it doesn't matter, bc the
task.outputs.files
is empty anyway
v
Hm, yeah, this seems to work fine and as expected:
Copy code
val foo by tasks.registering {
    val output = layout.buildDirectory.file("foo")
    outputs.file(output)
    outputs.upToDateWhen { false }
    doLast {
        output.get().asFile.writeText("foo")
    }
}
abstract class Bar : DefaultTask() {
    @get:InputFiles
    abstract val yamlFilesToMerge: SetProperty<FileSystemLocation>
    @TaskAction
    fun bar() {
        yamlFilesToMerge.get().forEach {  }
    }
}
val bar by tasks.registering(Bar::class) {
    outputs.upToDateWhen { false }
    yamlFilesToMerge = foo.get().outputs.files.asFileTree.filter { println("FOO"); it.name == "foo" }.elements
}
The
FOO
is only printed at execution time of
bar
after
foo
already executed and the file is there, also with clean worktree and CC used.
z
Yeah it's super confusing why this is happening to me
My workaround was to take the
KspTaskJvm.destinationDirectory
and add a new intermediary task that converted the
Directory
(
@InputDirectory
) into a
RegularFile
(
@OutputFile
) Not sure why I had to do that, but it is what it is!
t
what if you do a taskProvider.map { it.outputs.etc()} rather than a get and read of it?
z
@TrevJonez my example was actually the internal part of the task provider map function
v
Can you show the whole thing then? If I understood correctly you just revealed the missing piece you were hiding.