Does anyone know how to inject environment variabl...
# compose-desktop
b
Does anyone know how to inject environment variables into a desktop application during build time? we have some secrets we don't want to include in the GitHub repo because it's open source but we want them available in our binaries... does anyone have a good solution for this? πŸ‘€
πŸ‘ 1
c
m
If you package using Conveyor it's easy to do that, something like:
app.jvm.system-properties.myProp = ${<http://env.MY|env.MY>_SECRET}
. To do it with the default packaging, I guess you could write some Gradle code to read the env vars and set a JVM flag that defines a system property only when that env var is present in the build environment.
πŸ‘ 1
c
I like to use
.properties
files that are
.gitignored
, and access them in the gradle build as so: //
build.gradle.kts
(:composeApp)
Copy code
val props: Properties = Properties()
props.load(project.file("./../local.properties").inputStream())
identity.set(props.getProperty("SIGNING_IDENTITY")) // example use of the property value
and in the
local.properties
file:
Copy code
SIGNING_IDENTITY=Chris Athanas
I also like to keep a
local.properties.example
file and check this in to source control, as a placeholder and reminder what the contents of the file should look like and where it should sit in the directory structure (its so annoying to figure this out without doing this): //
local.properties.example
(check this into source control)
Copy code
SIGNING_IDENTITY=<YOUR_NAME_HERE>
βž• 1
m
I prefer switching between .properties file and environment variables. Locally I have a local.properties file with all the needed variables. And if I need to build the app on github using actions I set them with github environment variables and this approach works well with BuildKonfig library. You can create variables with the library and try to get them from local.properties file if the variable doesn't exist you can try to get it from environment variables using System.getEnv("VARIABLE_NAME").
πŸ‘ 1
s
For Ashampoo Photo Organizer I made something that may seem to easy and doesn't need a plugin. πŸ˜„ You can use Gradle to create any code you want and put it under "generated". That's what the Android plugin does, too.
Copy code
// region AppApiKeys
project.afterEvaluate {

    logger.lifecycle("Generate AppApiKeys.kt")

    val outputDir = layout.buildDirectory.file("generated/source/commonMain/com/ashampoo/photos/").get().asFile

    outputDir.mkdirs()

    val file = File(outputDir.absolutePath, "AppApiKeys.kt")

    val keyNames = listOf(
        "SENTRY_ANDROID_DSN", "SENTRY_DESKTOP_DSN", "SENTRY_IOS_DSN", "SENTRY_MACOS_DSN"
    )

    file.printWriter().use { writer ->

        writer.println("package com.ashampoo.photos")
        writer.println()

        for (keyName in keyNames) {

            var keyValue = System.getenv(keyName)

            if (keyValue == null)
                keyValue = ""

            writer.println("const val $keyName: String = \"$keyValue\"")
        }

        writer.flush()
    }
}
// endregion
πŸ‘ 1
c
The only thing is that
afterEvaluate
is bad practice and should be avoided. You should rather put that in a plugin or register a task that runs at the right time.
s
At the time I wasn't able to make it work otherwise, so I stayed with that solution.
πŸ‘ 1
How would the proper solution look like? Do you have sample code?
πŸ‘ 1
c
Check the plug-in I posted. It does what you do just in a better way πŸ˜…
πŸ‘ 1
s
I don't need an extra plugin for that. πŸ€·β€β™‚οΈ I like simple solutions. πŸ™‚ Can't invest the time right now to look for another solution.
c
If you do it the proper way, you need a plug-in, πŸ˜…
s
Objection! Whenever possible I avoid libraries and plugins. These are dependencies I need to take care of. And if they have a bug I need to invest time looking for a solution. If the people maintaining it decide to not do that any longer, you have to look for alternatives. For simple things that don't need a lib or a plugin like this I prefer simple solutions.
πŸ‘ 1
c
You need a task that runs before the compile task. To achieve that you need to register that task with a gradle plug-in. πŸ˜‰
s
18 years ago as I started my career I was very much into using libraries for everything, but over the time libraries were not supported anymore and the cost of changing them was too high. So my old product (as old as my career) depended for many years on old Swing libs that were no longer maintained and prevented updating to Java 8. That teached me! You can believe that! I use libraries where the cost of creating something of my own is just too high, but I don't use libraries for the simplest things like this topic at hand here, DI or even logging.
πŸ‘ 2
c
πŸ‘πŸ»
πŸ‘ 1
c
Excellent nuanced and useful conversation guys! @Chrimaeon What is the exact reason to avoid the
afterEvaluate
solution? Forgive me, I’m a gradle user and not a gradle expert by any means.
c
search in the #gradle channel there are several discussion around this.
πŸ‘ 1
h
Creating a Gradle to task to generate source code and wire it correctly is very easy: https://github.com/hfhbd/kobol/blob/main/gradle/build-logic/src/main/kotlin/StoreVersion.kt
Copy code
val storeVersion by tasks.registering(StoreVersion::class)
sourceSets.main {
    kotlin.srcDir(storeVersion)
}
πŸ™ 1
496 Views