I have a json file in my project that I want to us...
# gradle
e
I have a json file in my project that I want to use to generate some code when building. That code would be used by my project, but no existing code would be modified. Would I need a compiler plugin, or would a regular Gradle plugin work for something like this? In either case, can anyone point me towards a tutorial/documentation for this, or another project that does something similar?
f
Regular task is enough, basically you need a task with an input file, output directory, register the output as source set, register the output as generated in idea plugin, make compileKotlin dependOn. Example? Protobuf plugin 😊
v
Regular task is enough
Check
a task with an input file, output directory
Check
register the output as source set
No, register the task itself as
srcDir
for a source set, this also adds an implicit task dependency automatically whenever the sources are needed.
register the output as generated in idea plugin
Optional, but check
make compileKotlin dependOn.
No, better do as advised above, there are for example also other tasks that need sources like a source jar task and so on. Always better going with an implicit task dependency if possible.
Example?
This is how you properly register a source generation task as source files:
Copy code
val mySourceGeneratingTask by tasks.registering(...) {
     ...
 }
 
 val generate by tasks.registering {
     dependsOn(mySourceGeneratingTask)
 }
 
 sourceSets {
     main {
         java {
             srcDir(mySourceGeneratingTask)
         }
     }
 }
TheĀ generateĀ task is fully optional, but I like to have a lifecycle task that depends on all tasks that generate something.
e
Thanks all!
f
@Vampire didn't know that I can register a task as a source directory. Where does it take the directory from? Seems like you created an ordinary
org.gradle.api.Task
there, or should it be a specific one?
v
The task type is not important. The important thing is, that you have an output directory property that has the root for the generated sources as value. The output directory will be the source directory
f
I hoped for that. šŸ™‚ Pretty awesome, something new every day. šŸ˜‰ šŸ‘
e
@Vampire I just started on this; does this look generally correct?
Copy code
@CacheableTask
open class GenerateTask : DefaultTask() {
  @get:InputFile
  @PathSensitive(PathSensitivity.RELATIVE)
  val inputFile: File = project.file("src/main/assets/file.json")

  @get:OutputFile
  val outputFile: File = project.file("build/generated/File.kt")

  @TaskAction
  fun generate() {
    outputFile.writeText(inputFile.readText())
  }
}

val generatorTask by tasks.registering(GenerateTask::class)

val generate by tasks.registering {
  dependsOn(generatorTask)
}

android.sourceSets {
  getByName("main") {
    java {
      srcDir(generatorTask.get().outputFile)
    }
  }
}
And that would make any task that requires source run my task? And if I wanted to have an IDEA plugin that would run this task if it detects source changes, I would have it invoke the
generate
task or the
generatorTask
?
v
Besides that I question some design decisions like for example using
File
instead of for example
RegularFileProperty
, I ignore that, as your task seems to be just a quick and dirty playground anyway. Regarding the wiring, that looks ok, except for the part that you did not go like I suggested, except if Android is not capable of doing it the normal way, but no have no idea about Android development. Your IJ plugin would of course invoke the
generatorTask
. As I said, the
generate
task is a fully optional lifecycle task I like to have that depends on all tasks that generate something. It would be ridiculous to call that from your IJ plugin just because one of the generate tasks is outdated.
e
Oh good to know about
RegularFileProperty
, wasn't aware of that. Regarding
getByName("main")
I was getting errors if I used
main
both with
sourceSets
and
android.sourceSets
. Regarding
srcDir
I originally had it like you did, but then I was trying a few different things because the task wasn't getting invoked when I thought it should (like before a build, etc...). I think I did something wrong elsewhere, so I still need to play around with it some more.
Actually it looks like Android only accepts files for
srcDir
v
Oh good to know aboutĀ 
RegularFileProperty
, wasn't aware of that.
https://docs.gradle.org/current/userguide/lazy_configuration.html Imho every new task / extension / plugin should use that. šŸ™‚
RegardingĀ 
getByName("main")
Ā I was getting errors if I usedĀ 
main
both withĀ 
sourceSets
Ā andĀ 
android.sourceSets
.
It was from a Java or Kotlin project where the
main
source set exists and is available as type-safe accessor. Obviously for Android this does not work and the normal source set is not available with Android, so the
getByName
is probably ok, even though I'd normally use the lazy api everywhere (
named
). But probably that collection is not evaluated lazily anyway, so
getByName
is probably ok too. I just tend to always use the new api for consistency and future proofness.
Actually it looks like Android only accepts files forĀ 
srcDir
As I said, I didn't really touch Android dev yet, my code was from normal project. But from a quick look you are right.
AndroidSourceDirectorySet#srcDir
evaluates according to
Project#file
while
SourceDirectorySet#srcDir
evaluates according to
Project#files
and only the latter allows `Task`s directly as tasks can have multiple output properties. But by doing
srcDir(generatorTask.get().outputFile)
I think you loose the implicit task dependency as you unwrap the provider and additionally you make the task be realized immediately instead of lazily. When keeping the property as
File
, I think the correct way while staying lazy and keeping the implicit task dependency should
srcDir(generatorTask.map { it.outputFile })
. And if you switch to the recommended
RegularFileProperty
or
Provider<RegularFile>
(if it should not be editable), then either the same should work, or alternatively
srcDir(generatorTask.flatMap { it.outputFile })
.
e
Thanks! Looks like I have some reading up to do on keeping things lazy