alef 0.79.1

Opinionated polyglot binding generator for Rust libraries
Documentation
// Registered by alef, one time, via `--init-script`. Not part of the consumer's build; alef never
// writes this file into the consumer's tree.
//
// Prints every `compile*Kotlin` task's resolved classpath and its own destination directory, one
// entry per line as `ALEF_CLASSPATH_ENTRY:<absolute path>`. Matched by task name rather than by
// Kotlin Gradle plugin type, so this needs no Kotlin/AGP classes on the init-script classpath and
// covers both the plain `kotlin("jvm")` plugin and every Android build variant alike.
//
// The match uses `=~` (find), not `==~` (full match): Kotlin Multiplatform compile task names put
// the target *after* `Kotlin` -- `compileKotlinJvm`, `compileKotlinIosArm64`, `compileKotlinJs` --
// so a full-string match against `compile.*Kotlin` silently excludes every one of them and every
// dependency (including transitive ones) reachable only through that target's classpath. `=~`
// matches the same single-target task names (`compileKotlin`, `compileDebugKotlin`) it always did,
// plus these. ~keep
//
// Each matched task also prints an unconditional `ALEF_CLASSPATH_TASK:<name>` marker before either
// try/catch below runs, so the Rust side can tell a resolution that legitimately found few
// dependencies apart from one where a task matched but its classpath/library property silently
// contributed nothing: every real Kotlin compilation depends on kotlin-stdlib at minimum, so a
// matched task contributing no more than its own destination directory is a resolution defect, not
// a small project. ~keep
//
// A compile task's own `libraries`/`classpath` property mirrors that variant's `compileClasspath`
// configuration, which by Gradle's own `api`/`implementation` design only exposes a dependency's
// `api`-scoped transitive dependencies -- an `implementation`-scoped transitive dependency stays
// invisible there even though it is a real, resolvable artifact the module ships with, because it
// also appears on that variant's `runtimeClasspath`. A doc snippet demonstrating a capability the
// module gets from such a dependency is not bound by the module's own internal api/implementation
// boundary the way the module's own source is, so this also unions in every `*RuntimeClasspath`
// configuration once a project has at least one matched Kotlin compile task, resolved leniently so
// one unresolvable artifact cannot silently drop every other real dependency the configuration
// would otherwise report. Matched by name suffix rather than a hardcoded variant name so this
// covers Android's per-variant configurations (`debugRuntimeClasspath`, `releaseRuntimeClasspath`,
// ...), a plain JVM project's single `runtimeClasspath`, and Kotlin Multiplatform's per-target ones
// alike. ~keep
allprojects { proj ->
    proj.tasks.register("alefPrintClasspath") {
        doLast {
            def entries = new LinkedHashSet<String>()
            def matchedAnyTask = false
            proj.tasks.matching { it.name =~ /(?i)compile.*Kotlin/ }.each { compileTask ->
                matchedAnyTask = true
                println "ALEF_CLASSPATH_TASK:" + compileTask.name
                try {
                    if (compileTask.hasProperty('destinationDirectory')) {
                        entries << compileTask.destinationDirectory.get().asFile.absolutePath
                    }
                } catch (Exception ignored) {
                    // Best-effort: a task that does not expose this property contributes nothing.
                }
                try {
                    def classpath = compileTask.hasProperty('libraries') ? compileTask.libraries
                        : (compileTask.hasProperty('classpath') ? compileTask.classpath : null)
                    if (classpath != null) {
                        classpath.files.each { entries << it.absolutePath }
                    }
                } catch (Exception ignored) {
                    // Best-effort: a task that does not expose either property contributes nothing.
                }
            }
            if (matchedAnyTask) {
                proj.configurations.matching { configuration ->
                    configuration.canBeResolved && configuration.name.toLowerCase().endsWith('runtimeclasspath')
                }.each { configuration ->
                    try {
                        configuration.incoming.artifactView { viewConfiguration -> viewConfiguration.lenient(true) }
                            .files.each { artifact ->
                                // An Android runtime classpath can report `.aar` archives, which kotlinc cannot
                                // read as classpath entries; a plain jar or a classes directory is what every
                                // compile-task classpath above already contributes. ~keep
                                if (artifact.isDirectory() || artifact.name.toLowerCase().endsWith('.jar')) {
                                    entries << artifact.absolutePath
                                }
                            }
                    } catch (Exception ignored) {
                        // Best-effort: a configuration that cannot resolve even leniently contributes nothing.
                    }
                }
            }
            entries.each { println "ALEF_CLASSPATH_ENTRY:" + it }
        }
    }
}