Hi everyone :slightly_smiling_face:, I'm newish to...
# community-support
r
Hi everyone 🙂, I'm newish to java / gradle so forgive me if this is a rudimentary question. What's the recommended approach for running one off tasks that aren't apart of the main application build? Kind of similar to running npm / yarn scripts. For example, I'm able to require the xmlbeans project (org.apache.xmlbeansxmlbeans5.2.1) and register a custom JavaExec task (named
createXSD
) that invokes the
org.apache.xmlbeans.impl.inst2xsd.Inst2Xsd
class. And i'm looking the ability to wrap this task/class so that I can call it via the cli like:
./gradlew createXSD --file {path-to-xml}
Where
--file
is a custom input parameter for my custom registered task which passes that down the corresponding args to Inst2Xsd.
The closest i could find was the internet suggesting I can use
-P
flag to set a property configuration value and use that in my custom task which could work, but I was wondering if there was a better way to do this or if i'm thinking about gradle incorrectly in general
v
Well, write a task with an
@Option
, then you can do exactly the
./gradlew createXSD --file {path-to-xml}
you are after. Using
-P
is just a cheap work-around and bad as they are global and not targeted at a task.
r
I tried doing the custom task route like that, but i wasn't able to invoke the JavaExec task to actually invoke the specific java class with args.
v
Well, you did it wrong then it seems. 🙂
r
hehe
Copy code
abstract class CreateXSD : DefaultTask() {
    @TaskAction
    fun run() {
        println("wow")

        val test = object : JavaExec() {}
//        exec.classpath(xmlbeans)
//        exec.mainClass = "org.apache.xmlbeans.impl.inst2xsd.Inst2Xsd"
//        exec.args = listOf("-h")
//        exec.exec()
    }
}
I tried something like this
v
That's indeed very very very very wrong
r
lol
ya i figured my mental model for gradle is not quite right
v
Either make
CreateXSD
a subclass of
JavaExec
or use
ExecOperations.javaExec { ... }
in your task action, but do not create an anonymous subclass of
JavaExec
or any other task like that
You do never "call" a task either
ok, i think this definitely helps!
👌 1
Copy code
abstract class CreateXSD
    @Inject
    constructor(
        private val execOps: ExecOperations,
    ) : DefaultTask() {
        @Input
        @Option(option = "file-name", description = "XML file to generate xsd from")
        lateinit var fileName: String

        @TaskAction
        fun run() {
            execOps.javaexec {
                classpath(project.configurations.named("xmlbeans"))
                mainClass = "org.apache.xmlbeans.impl.inst2xsd.Inst2Xsd"
                args = listOf(
                    "-design",
                    "ss",
                    "-simple-content-types",
                    "smart",
                    "-outDir",
                    "src/main/resources/xml",
                    "-enumerations",
                    "never",
                    xmlPath(fileName),
                )
            }

            val src = project.file(xmlPath("schema0.xsd"))
            val dst = project.file(xmlPath(fileName.replace(".xml", ".xsd")))

            src.renameTo(dst)
        }

        private fun xmlPath(name: String) = "src/main/resources/xml/$name"
    }

tasks.register<CreateXSD>("createXSD")
Amazing! this code works:
./gradlew createXSD --file-name=example.xml
Thanks for the help!
v
You should also properly define your inputs and outputs, otherwise the task can never be up-to-date.
And task properties as well as extension properties should better always be lazy types like
Property<String>
and never "primitive" types.
But generally, yes. 🙂