Is it possible to get the root path of the project...
# multiplatform
j
Is it possible to get the root path of the project (as a string) in commonTest?
b
In a gradle file or in Kotlin?
i guess if you're asking about commonTest, you mean Kotlin
j
Basically I need to be able to access the files in
project/src/commonTest/resources/
i have file reader actuals implemented in jvm/ios/js
in jvm i can do
val filePath: String = System.getProperty("user.dir") + "/src/commonTest/resources/" + fileName
but i can't do that in js or ios obviously
b
In your build, you can codegen a Kotlin file that has that constant (in an
object
or something). You'd spit out that file in your
build
dir somewhere and then add that folder to your commonTest sourceSet
j
is that complicated to do?
or relatedly, is it possible to make values declared in build.gradle.kts available in kotlin sources?
b
I believe this is generally the way it's done. It's basically what android gradle plugin does
with
BuildConfig
. one sec. sample code coming
j
ok sweet thanks!
b
Copy code
afterEvaluate {
    tasks.register("generateTheCodes") {
        def packageRoot = file("build/mycodgen/kotlin/com/<package-path>")
        def buildConfigFile = new File(packageRoot, "BuildConfig.kt")
        outputs.file(buildConfigFile)

        doLast {
            // make the directory tree
            mkdir packageRoot

            buildConfigFile.text = ""

            buildConfigFile << """package <your-package>
              |object MyBuildConfig {
              |    const val resourcesPath = ${file("src/commonTest/resources").path}              
              |}
            """.stripMargin().stripIndent()
        }
    }

    // Include this in our source sets
    kotlin.sourceSets.named("commonTest") {
        kotlin.srcDirs += uidsRoot
    }
    // Ensure this runs before any compile task
    tasks.withType(AbstractCompile.class).each {
        it.configure {
            dependsOn 'generateTheCodes'
        }
    }
}
this creates a task called
generateTheCodes
which outputs a .kt file that has an
object
in it, then at the end we add it to commonTest sources and add it to the task graph (with a bit of a broad brush, but should work fine)
j
you're the man
b
there are some things that you'll have to adjust for your case like the package paths and all that, but hopefully this gives a good start
j
let me try it out
thank you!
b
codegen is great, once you get the hang of it. you can save yourself a lot of time making it part of your teams workflow to automate common classes, etc.
j
oh definitely. i'm just new-ish to kotlin
but it's served well on other platforms
b
yeah no worries 🙂
j
hmm packageRoot should point to what exactly
b
com/mycompany/mylibrary/
j
inside of the build folder though?
or is the build meaningless in the sample
b
oh yeah so inside the build folder, pick a name that makes sense for your root for this codegen
like
build/mybuildconfig
j
gotcha
b
and then source will be
build/mybuildconfig/com/mycompany/mypackage/
basically mirroring package/folder structure in your lib
j
ok trying that now
last q: what is
uidsRoot
supposed to point to?
i guess packageRoot
b
oh yeah sorry. i was adapting some personal code and forgot to fix that var name
uidsRoot is `build/mybuildconfig`` in this case
so not package root
j
@basher It's almost working! The `BuildConfig.kt`gets created in
build/<package>
, but I still can't reference
BuildConfig.resourcesPath
from the files in
commonTest
(suggesting that something's not working with adding the dir to the sourceset)?
b
does the BuildConfig.kt have the right package declaration at the top?
and you're adding bulid/mybuildconfig to commonTest right? not the full path?
j
yea it does. this is what i got
Copy code
afterEvaluate {
    val generateBuildConfig = tasks.register("generateBuildConfig") {
        val packageRoot = file("build/codegen/kotlin/com/n8p6/enkounter/")
        val buildConfigFile = File(packageRoot,"BuildConfig.kt")
        outputs.file(buildConfigFile)

        doLast {
            mkdir(packageRoot)

            buildConfigFile.writeText("""
                package com.n8p6.enkounter
                
                object BuildConfig {
                    const val resourcesPath: String = "${file("src/commonTest/kotlin/com/n8p6/enkounter/resources").path}"
                }
                """.trimMargin().trimIndent()
            )
        }
    }

    kotlin.sourceSets.named("commonTest") {
        kotlin.srcDirs += file("build/codegen/kotlin/com/n8p6/enkounter")
    }

    tasks.withType<AbstractCompile>().forEach {
        it.dependsOn(generateBuildConfig)
    }
}
b
one thing to be careful of is that if you have an Android target, Android also makes an object called BuildConfig (may want to consider a prefix)
j
ah i don't
but might be worth changing regardless just to be safe
b
kotlin.srcDirs += file("build/codegen/kotlin/com/n8p6/enkounter")
should be
kotlin.srcDirs += file("build/codegen")
j
ohhh
i see what you meant
let me try that
b
🙂
j
finally got it with
commonTest.kotlin.setSrcDirs(commonTest.kotlin.srcDirs + "build/codegen")
thank you so much for your help @basher!
b
🎉 np!
r
FYI there's a library BuildKonfig that does some of this work for you if you want the configuration to feel more like an Android project. https://github.com/yshrsmz/BuildKonfig
👍 1
b
Ooh nice!
369 Views