Is it possible to have a custom Gradle task that e...
# gradle
n
Is it possible to have a custom Gradle task that exposes a function as part of the API?
I have a custom Gradle task which contains the following:
Copy code
open class FlatpakManifestTask : FlatpakManifestTaskBase, DefaultTask() {
    private val objFactory = project.objects
    @Input
    override val appId: Property<String> = objFactory.property()
    @Input
    override val command: Property<String> = objFactory.property()
    @Input
    override val runtime: Property<String> = objFactory.property()
    @Input
    override val runtimeVer: Property<String> = objFactory.property()
    @Input
    override val sdk: Property<String> = objFactory.property()
    @Input
    override val modules: ListProperty<Module> = objFactory.listProperty(Module::class.java)
    @Input
    override val renameIcon: Property<String> = objFactory.property()
    @Input
    override val renameDesktopFile: Property<String> = objFactory.property()
    @Input
    override val finishArgs: ListProperty<String> = objFactory.listProperty(String::class.java)
    @Input
    override val cleanup: ListProperty<String> = objFactory.listProperty(String::class.java)
    @Input
    override val cleanupCommands: ListProperty<String> = objFactory.listProperty(String::class.java)

    init {
        @Suppress("LeakingThis")
        renameDesktopFile.set("")
        @Suppress("LeakingThis")
        renameIcon.set("")
    }

    fun basicModule(init: BasicModule.() -> Unit): BasicModule {
        val result = BasicModule()
        result.init()
        modules.add(result)
        return result
    }

    private fun generateJsonRoot() = buildJsonObject {
        put("app-id", appId.get())
        put("command", command.get())
        put("runtime", runtime.get())
        put("runtime-version", runtimeVer.get())
        put("sdk", sdk.get())
        if (renameDesktopFile.get().isNotEmpty()) put("rename-desktop-file", renameDesktopFile.get())
        if (renameIcon.get().isNotEmpty()) put("rename-icon", renameIcon.get())
        addFinishArgs(this)
        addCleanup(this)
        addCleanupCommands(this)
    }

    private fun addCleanupCommands(builder: JsonObjectBuilder) {
        if (cleanupCommands.get().isNotEmpty()) {
            builder.putJsonArray("cleanup-commands") {
                cleanupCommands.get().forEach { item -> add(item) }
            }
        }
    }

    private fun addCleanup(builder: JsonObjectBuilder) {
        if (cleanup.get().isNotEmpty()) {
            builder.putJsonArray("cleanup") {
                cleanup.get().forEach { item -> add(item) }
            }
        }
    }

    private fun addFinishArgs(builder: JsonObjectBuilder) {
        if (finishArgs.get().isNotEmpty()) {
            builder.putJsonArray("finish-args") {
                finishArgs.get().forEach { item -> add(item) }
            }
        }
    }

    @TaskAction
    fun create() {
        val manifest = File("${project.rootDir.absolutePath}/${appId.get()}.json")
        if (!manifest.exists()) manifest.createNewFile()
        manifest.writeText("${generateJsonRoot()}")
    }
}
Below is a Functional test that I want to get working:
Copy code
// ...
private fun testTaskExists() = test("Task exists") {
        setup()
        val appId = "org.example.Hello"
        buildFile.writeText("""
            $pluginBlock
            
            flatpakManifest {
                appId = "$appId"
                command = "hello"
                runtime = "org.freedesktop.Platform"
                runtimeVer = "19.08"
                sdk = "org.freedesktop.Sdk"
                basicModule {
                    name = "hello"
                    simpleBuildSystem {}
                    fileSource {
                        path = hello.sh
                    }
                }
            }
        """.trimIndent())
        val result = GradleRunner
            .create()
            .withProjectDir(projectDir)
            .withPluginClasspath()
            .withArguments("flatpakLocalRepo")
            .build()
        result.output shouldContain "BUILD SUCCESSFUL"
        tearDown()
    }
Note that many of the classes/elements don't extend DefaultTask. Is there any way to have these classes/elements exposed to a Gradle user as part of the plugin API?
Below is one of the classes/elements that doesn't extend DefaultTask:
Copy code
class FileSource : Source {
    override val type: String = "file"
    var path: String = ""
}

fun fileSource(init: FileSource.() -> Unit = {}): FileSource {
    val source = FileSource()
    source.init()
    return source
}
v
And what is not working?
n
Importing elements from the Gradle plugin.
v
Can you elaborate a bit more? My crystal ball is at the repair shop. What did you try to do? What did you expect to happen? What happened instead? Was there an error message somewhere? ...?
n
I am trying to use elements (parts of the API like a top level function for example) from the Gradle plugin in a Gradle build script by importing them. What should be happening is all the imported elements are accessible in the build script. Instead none of the elements are imported, and there are error messages about the elements being missing even though they exist in the Gradle plugin.
v
Well, it should work. If the plugin is applied, the classes are on the class path. I fear it is hard to tell where you error is, without seeing the code / project