I'm trying to include a build metadata properties ...
# community-support
n
I'm trying to include a build metadata properties file generated at build-time in the main resources sourceset, but I'm not finding a nice way to configure this. I'm landing in between 2 different solutions and I'm not sure which one is preferable. See thread ๐Ÿงต
โœ… 1
Option 1:
Copy code
val writeBuildProperties by tasks.registering(WriteProperties::class) {
    property("commit", versioning.info.commit)
    property("version", project.version.toString())

    destinationFile = layout.buildDirectory.file("build-info.properties")
}

tasks.processResources {
    from(writeBuildProperties) {
        rename { "META-INF/$it" }
    }
}
This seems nice and terse, but it doesn't really tell gradle that the properties file should be considered part of the
sourceSets.main.resources
Option 2:
Copy code
val writeBuildProperties by tasks.registering(WriteProperties::class) {
    property("commit", versioning.info.commit)
    property("version", project.version.toString())

    destinationFile = layout.buildDirectory.file("build-info/META-INF/build-info.properties")
}

sourceSets.main {
    resources {
        srcDir(writeBuildProperties.get().outputs.files.singleFile.parentFile.parentFile)
    }
}
This option is clear about the sourceset, but it requires that ugly
parent
parent
thing to appease the srcDir method ๐Ÿค”
Which one would be preferable? Or is there a 3rd option that gives the best of both worlds?
t
I'd go with option 2 but adding a variable for
layout.buildDirectory.dir("build-info")
or something like that (I've never really used the project layout as I haven't wrapped my head around that directory property API yet) so the
srcDir
is easier to configure (except now you need to explicitly configure a
builtBy(writeBuildProperties)
)
e
still ugly but you could make that lazier
Copy code
srcDir(writeBuildProperties.flatMap { it.destinationFile.getAsFile().map { it.parentFile.parentFile } })
n
Thanks for the suggestions! In an ideal world, there would be a way to tell
srcDir
to take a single file output and put it in a folder of choice, but perhaps that's a bit too specific as a use case ๐Ÿคท I think I'll go with the
builtBy
approach as the "least ugly" solution:
Copy code
val buildInfoDir = layout.buildDirectory.dir("build-info")
val writeBuildProperties by tasks.registering(WriteProperties::class) {
    property("commit", versioning.info.commit)
    property("version", project.version.toString())

    destinationFile = buildInfoDir.map { it.file("META-INF/build-info.properties") }
}

sourceSets.main {
    resources {
        srcDir(files(buildInfoDir) { builtBy(writeBuildProperties) })
    }
}
v
There are at least two further options which probably both are a bit nicer. 1. define another task, this time of type
Sync
, which `from`s the write properties task into the respective subdirectory where it is needed and you use the sync task as
srcDir
2. do not use a
WriteProperties
task, but just have a
...properties
file with placeholders in
src/main/resources
and use
expand
on
processResources
to fill in the placeholders I usually use the latter unless there are strong reasons not to. This is also more compatible with running from IDE if you cannot or don't want to use Gradle delegation.
๐Ÿ‘ 1
n
Interesting, I'll see what the placeholder expansion can do. That seems like the cleanest solution without having to copy files all over the place ๐Ÿ‘
t
IIUC, limitation of expand is that it won't quote/escape your property values, but judging from your snippet it shouldn't be a problem here.
n
Indeed, it doesn't. Cleans up nicely as well:
Copy code
tasks.processResources {
    filesMatching("META-INF/edge-build-info.properties") {
        expand(
            "commit" to versioning.info.commit,
            "version" to project.version.toString()
        )
    }
}
Thanks again for the suggestions and ideas ๐Ÿ™
v
One thing to keep in mind as someone mentioned "escaping". The file is now the source for a Groovy template engine. So if you for example need a backslash or dollar sign (in the file, not in the injected value), you need to double it due to that. But on the other hand you can also do inline evaluation with full Groovy capabilities. If you don't like that, for example because the IDE might show these as errors, you could also name it
....properties.template
or whatever and add a
rename
, or use a more simplistic alternative like a line-based replacement from the build script, or using
ReplaceTokens
which also just does a text-replacement.
And don't forget to declare your task inputs. Currently the task would be up-to-date even if the values to be expanded change, they are not automatically inputs afair
๐Ÿ’ก 1