Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usages of afterEvaluate #120

Open
tylerbwong opened this issue Dec 7, 2024 · 2 comments
Open

Remove usages of afterEvaluate #120

tylerbwong opened this issue Dec 7, 2024 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@tylerbwong
Copy link
Owner

As mentioned in #117, this plugin should be reacting to other plugins as they're applied, instead of using a nondeterministic mechanism to wait until it thinks relevant plugins are applied.

@tylerbwong tylerbwong added the enhancement New feature or request label Dec 7, 2024
@tylerbwong tylerbwong self-assigned this Dec 7, 2024
@efemoney
Copy link
Contributor

efemoney commented Jan 11, 2025

I tried something locally (the code snippets use extensions I added but pls read as pseudocode)

The goal is to have a full picture of the module at the time when the metalava plugin needs it, what I did:

  • Gather all supported plugins as early as possible into a list,
val support = objects.listProperty<SupportedPlugin>()

withJavaPlugin { support.add(Java(java)) } // not java-library, just java, which is also applied by kotlin-jvm for instance

withAnyKotlinPlugin { support.add(Kotlin(kotlin)) } // any of the ff kotlin plugins: kotlin-jvm, -android, -multiplatform

withAndroidLibraryPlugin { support.add(AndroidLibrary(androidComponents)) } // android-library only

afterEvaluate {
    if (support.get().isEmpty()) throw GradleException("No supported metalava plugins found.")
}
return SupportedPlugins(support)
  • Wait until as late as possible for each supported plugin to configure, this one checks only the specific supported plugins
withJavaLibraryPlugin { // java-library
    // necessary to after evaluate here so we are sure tasks are created after user code 
    // eg. in case new source sets are added
    afterEvaluate {
        println("Java library. ${java.sourceSets.toList()} $support")
    }
}
withAndroidLibraryPlugin { // android-library
    androidComponents {
        // Variants are created after buildscript evaluation so we can safely iterate & configure each one
        // Android has its own concept of sourceSets which can deduced from the variant names / buildtypes / flavors.
        onVariants { variant ->
            println("Android variant: ${variant.name}. $support")
        }
    }
}
withAnyKotlinPlugin { // both single & multiplatform
    /*
    Targets provide a good entry point for Multiplatform projects and for single-platform kotlin projects,
    the target is implicit, so the abstraction still works.
    Each target has a list of compilations which include variants of the main and test sourceSets.
     */
    kotlin.configureEachTargetCompilation {
        println("Kotlin target: ${target.targetName.ifEmpty { "{target}" }}/$name, $kotlinSourceSets. $support")
    }
}

The result:

> Configure project :samples:groovy-android
Android variant: debug. [AndroidLibrary]
Android variant: release. [AndroidLibrary]

> Configure project :samples:groovy-java
Java library. [source set 'main', source set 'test'] [Java]

> Configure project :samples:kotlin-dsl-android
Android variant: debug. [AndroidLibrary]
Android variant: release. [AndroidLibrary]

> Configure project :samples:kotlin-dsl-compose
Android variant: debug. [AndroidLibrary,Kotlin]
Android variant: release. [AndroidLibrary,Kotlin]
Kotlin target: {target}/debugAndroidTest, [source set debugAndroidTest, source set androidTest, source set androidTestDebug]. [AndroidLibrary,Kotlin]
Kotlin target: {target}/debugUnitTest, [source set debugUnitTest, source set test, source set testDebug]. [AndroidLibrary,Kotlin]
Kotlin target: {target}/debug, [source set debug, source set main]. [AndroidLibrary,Kotlin]
Kotlin target: {target}/releaseUnitTest, [source set releaseUnitTest, source set test, source set testRelease]. [AndroidLibrary,Kotlin]
Kotlin target: {target}/release, [source set release, source set main]. [AndroidLibrary,Kotlin]

> Configure project :samples:kotlin-dsl-empty
Kotlin target: {target}/main, [source set main]. [Java,Kotlin]
Kotlin target: {target}/test, [source set test]. [Java,Kotlin]

> Configure project :samples:kotlin-dsl-kotlin
Kotlin target: {target}/main, [source set main]. [Java,Kotlin]
Kotlin target: {target}/test, [source set test]. [Java,Kotlin]

> Configure project :samples:kotlin-multiplatform
Kotlin target: metadata/main, [source set commonMain]. [Kotlin,AndroidLibrary]
Kotlin target: iosX64/main, [source set iosX64Main]. [Kotlin,AndroidLibrary]
Kotlin target: iosX64/test, [source set iosX64Test]. [Kotlin,AndroidLibrary]
Kotlin target: iosArm64/main, [source set iosArm64Main]. [Kotlin,AndroidLibrary]
Kotlin target: iosArm64/test, [source set iosArm64Test]. [Kotlin,AndroidLibrary]
Kotlin target: iosSimulatorArm64/main, [source set iosSimulatorArm64Main]. [Kotlin,AndroidLibrary]
Kotlin target: iosSimulatorArm64/test, [source set iosSimulatorArm64Test]. [Kotlin,AndroidLibrary]
Kotlin target: js/main, [source set jsMain]. [Kotlin,AndroidLibrary]
Kotlin target: js/test, [source set jsTest]. [Kotlin,AndroidLibrary]
Kotlin target: jvm/main, [source set jvmMain]. [Kotlin,AndroidLibrary]
Kotlin target: jvm/test, [source set jvmTest]. [Kotlin,AndroidLibrary]
Kotlin target: linuxX64/main, [source set linuxX64Main]. [Kotlin,AndroidLibrary]
Kotlin target: linuxX64/test, [source set linuxX64Test]. [Kotlin,AndroidLibrary]
Android variant: debug. [Kotlin,AndroidLibrary]
Android variant: release. [Kotlin,AndroidLibrary]
Kotlin target: android/debugAndroidTest, [source set androidInstrumentedTestDebug, source set androidInstrumentedTest]. [Kotlin,AndroidLibrary]
Kotlin target: android/debugUnitTest, [source set androidUnitTestDebug, source set androidUnitTest]. [Kotlin,AndroidLibrary]
Kotlin target: android/debug, [source set androidDebug, source set androidMain]. [Kotlin,AndroidLibrary]
Kotlin target: android/releaseUnitTest, [source set androidUnitTestRelease, source set androidUnitTest]. [Kotlin,AndroidLibrary]
Kotlin target: android/release, [source set androidRelease, source set androidMain]. [Kotlin,AndroidLibrary]
Kotlin target: metadata/appleMain, [source set appleMain]. [Kotlin,AndroidLibrary]
Kotlin target: metadata/commonMain, [source set commonMain]. [Kotlin,AndroidLibrary]
Kotlin target: metadata/iosMain, [source set iosMain]. [Kotlin,AndroidLibrary]
Kotlin target: metadata/nativeMain, [source set nativeMain]. [Kotlin,AndroidLibrary]

@efemoney
Copy link
Contributor

efemoney commented Jan 11, 2025

The cases that need to be supported include

  • java-library only
  • kotlin (ie kotlin jvm) only (applies java underneath)
  • android-library only
  • android-library + kotlin-android
  • kotlin-multiplatform + android-library

Currently, this plugin creates a single task set (task set represents the set of check & generate metalva tasks) for projects that do not apply android, and a task set per variant for android projects.

This was okay when users where asked to manually specify source folders, the responsibility was on the users to figure out how to add the correct sourceSets, but this does not work with this plugin's automatic configuration and in fact its confusing in the case where kotlin is applied with other plugins (most especially kmp)

I think it would be better to explicitly define what is supported (for kmp, are all targets supported or just the jvm & android targets), and in the kotlin cases, work with targets/compilations & not just sourceSets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants