This message was deleted.
# community-support
s
This message was deleted.
a
it really depends on how you want to use this environment variable. If you’re launching a JVM process, then you can set an environment variable for that process based on a property from
gradle.properties
. Or if you just want some variable that might come from
gradle.properties
on one machine, but is set via an environment variable on another machine, then you can use a project property Can you explain more about what you want to achieve?
s
Sure. I'm using JGit programmatically directly as part of my
build.gradle.kts
file. When probing for the Git system config, JGit eventually calls out to the system's
git
CLI, which is incompatible with Gradle's new configuration caching. JGit's behavior can be suppressed by setting the
GIT_CONFIG_NOSYSTEM
environment variable, and that's what I'd like to do.
a
funnily enough I’m also trying to work around that JGit issue at the moment! It would be nice to have a build service for Git operations that was config-cache compatible
the only suggestion I have to set that environment variable for JGit is to try and use a build listener https://docs.gradle.org/current/javadoc/org/gradle/BuildListener.html but the problem is, what happens if a Gradle is cancelled, or crashes? The ‘unset’ operation might not be called.
s
Looks like an alternative could be use a custom FS that makes
getGitSystemConfig
return null.
a
Can you wrap jgit call to ValueSource and can that make it compatible with cc?
More about ValueSource can be found in cc docs: https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements:external_processes Basically idea is, that ValueSource can run anything, and it makes that “anything” cc compatible. And it invalidates configuration cache only when result of obtain method is changed. But it is important that whatever is in ValueSource is a fast operation, since it’s not cached.
s
@Anze Sodja I tried with a top-level class in my
build.gradle.kts
file but I'm getting
Copy code
* What went wrong:
Could not create an instance of type Build_gradle$GitVersionValueSource.
> Class Build_gradle.GitVersionValueSource is a non-static inner class.
Looks like the problem is that I capture
rootDir
from the outer scope. What do I need to inject as a property to get access to the project?
a
You need to pass what you want to use in ValueSource via parameters, e.g.:
Copy code
// Kotlin
abstract class MyValueSource : ValueSource<String, MyValueSource.MyValueSourceParams> {

    private val logger = Logging.getLogger(MyValueSource::class.java)

    interface MyValueSourceParams : ValueSourceParameters {
        val rootDir: DirectoryProperty
    }

    override fun obtain(): String {
        logger.lifecycle("In value source: " + parameters.rootDir.get().asFile.path)
        return parameters.rootDir.get().asFile.path
    }
}

val provider = providers.of(MyValueSource::class) {
    parameters {
        rootDir.set(project.rootDir)
    }
    // or just parameters.rootDir.set(project.rootDir)
}

println(provider.get())
But you can’t pass Project and similar complex structures (e.g. Configuration)
s
Thanks. As I have several JGit calls that each would require a separate
ValueSource
, I decided to go with the solution of a custom
SystemReader
as mentioned at https://stackoverflow.com/a/59110721/1127485 instead.
👍 1
v
I'm maybe a bit late to the party, but this works perfectly fine and only needs one
ValueSource
to bootstrap JGit if a new Daemon was started with not missing the system config which the SO answer causes:
Copy code
import org.eclipse.jgit.storage.file.FileRepositoryBuilder

plugins {
    id("org.ajoberstar.grgit.service") version "5.2.0"
}

abstract class JGitBootstrapper : ValueSource<String, JGitBootstrapper.Parameters> {
    override fun obtain(): String {
        FileRepositoryBuilder()
            .setWorkTree(parameters.projectDirectory.get().asFile)
            .build()
        return ""
    }

    interface Parameters : ValueSourceParameters {
        val projectDirectory: DirectoryProperty
    }
}

providers.of(JGitBootstrapper::class) {
    parameters {
        projectDirectory.set(layout.projectDirectory)
    }
}.get()

println(grgitService.service.get().grgit.head().id)
This way the external proess execution at configuration time is properly wrapped in a
ValueSource
, and it is only done once in the daemon lifetime as it is done as part of a static initialization. The actual Git operations done at configuration time then cause the accessed files and environment variables to be configuration cache inputs as usual. So if you execute this snippet two times, the second time nothing is printed. If you then create a new commit and rerun without other changes, it is rerun and prints again.
👍 1
Diese Nachricht enthält interaktive Elemente.
Diese Nachricht enthält interaktive Elemente.
And this is not even enough, because if I now change some source file, the dirty-state should change. So practically any file in the project should be a configuration cache input and thus make the cache void. Having this Git operation in a
ValueSource
instead, will execute the operation on every build and if changed even twice, but only the final result is considered an input, so the remaining configuration phase can be skipped more often. As this dirty-determination for me is then used in
processResources
to fill in a placeholder in a properties file, there would be almost no case where the configuration cache could be reused if all files of the project would properly be input.
So it might be much better for overall performance if operations are indeed be done in a value source