Vladimir Sitnikov
04/28/2025, 7:22 AMConfigurableFileCollection vs ListProperty<RegularFile>
Is there anything like “prefer ConfigurableFileCollection in newer code” or “prefer ListProperty<RegularFile> in newer code” ?
I assume the answer should be the same for both task properties and extension properties, however, it would be great to learn if there’s a difference.Vampire
04/28/2025, 7:24 AMVladimir Sitnikov
04/28/2025, 9:31 AMListProperty<RegularFile> usages while I previously sticked to ConfigurableFileCollection, so I decided to ask.
---
I saw AGP was migrating off FileCollection, however, it looks like there was no CFC#finalizeValue() back then.Vampire
04/28/2025, 11:52 AMConfigurableFileCollection to Provider<...> is because they want to lazify everything by using `Provider`s, but that is then just a misunderstanding, as ConfigurableFileCollection is properly lazy already and if you need its contents as Provider<...>, you can use FileCollection#elements.Vampire
04/28/2025, 11:54 AMConfigurableFileCollection to Property predates the FileCollection.elements method, so maybe back then it could have made sense. 🤷♂️Martin
04/28/2025, 2:03 PMRegularFile?Martin
04/28/2025, 2:04 PMConfigurableFileCollection can be "rooted" (if they are built from FileTree). I don't think you can do the same with RegularFile?Martin
04/28/2025, 2:05 PM*.graphql in the hierarchy at src/main/graphql to a task but that graphql path is not important. It could very well be under build/foobar/graphql and the snapshotting should be exactly the same as long as the contents of the folder stays the same. You just can't do this with a ListProperty<RegularFile>Emmanuel Guerin
04/29/2025, 3:16 PMFileCollection to a Provider<RegularFile> when it is expected the collection only has a single element.
For example in the case of a Task that has a RegularFileProperty as input, and it needs to be passed something coming from a dependency resolution.
The best I have so far is this:
fun setFilePropertyFromCollection(fileProperty: RegularFileProperty, collection: FileCollection) {
fileProperty.fileProvider(collection.elements.map {
it.singleOrNull()?.asFile ?: throw IllegalArgumentException("FileCollection must contain exactly one element")
})
}
This seems to keep the task dependencies and all the right things. Do you have anything better?
But this transforms FileCollection to a Provider<File>. I don't know how it can be transformed into a Provider<RegularFile>.Martin
04/29/2025, 3:39 PMFile into a RegularFile is tricking Gradle dependency injection:
abstract class Unused @Inject constructor( val files: FileFactory)
fun setFilePropertyFromCollection(collection: FileCollection): Provider<RegularFile> {
val factory = objects.newInstance(Unused::class.java)
return collection.elements.map {
val file = it.singleOrNull()?.asFile ?: throw IllegalArgumentException("FileCollection must contain exactly one element")
check(file.isFile)
factory.files.file(file)
}
}Martin
04/29/2025, 3:39 PMProvider<File> though 🤷Vladimir Sitnikov
04/29/2025, 3:41 PMlayout.file(provider { File(".") }?
See https://chatgpt.com/share/6810f339-92ec-800f-8edd-89b32dbf93a6Martin
04/29/2025, 3:42 PMMartin
04/29/2025, 3:43 PMRegularFileProperty and Provider<RegularFile>Vladimir Sitnikov
04/29/2025, 3:44 PMProperty<RegularFile> vs RegularFileProperty?
The Provider<..> does not have setter methods,Martin
04/29/2025, 3:45 PMMartin
04/29/2025, 3:46 PMProvider and Property, all the specialized classes like ListProperty as well are complexifying stuff
But I'm rambling, don't mind meVladimir Sitnikov
04/29/2025, 3:46 PMVampire
04/29/2025, 5:08 PMval files: FileCollection = null!!
val fileProperty: RegularFileProperty = null!!
val file: Provider<RegularFile?> = layout.file(files.elements.map { it.single().asFile })
fileProperty.set(file)