What's the best way to remove extraneous outputs f...
# community-support
m
What's the best way to remove extraneous outputs from a task? Context: • I'm passing a task to
srcDir()
; the sources root should be, e.g.,
generated/sources/openApiClient/java/main
. • However, the actual sources root is `generated/sources/openApiClient`; this is because the task generates other (unneeded) files in this directory. • Having an incorrect sources root causes weird behavior in IntelliJ (and possibly other IDEs). Here's the relevant excerpt:
Copy code
sourceSets {
    main {
        java {
            srcDir(tasks.named("openApiJavaGenerateServer"))
            srcDir(tasks.named("openApiJavaGenerateClient"))
        }
    }
}
Let's start with the BAD way to do it. First, we rewire the tasks:
Copy code
tasks.withType<JavaCompile> {
    dependsOn("openApiJavaGenerateServer", "openApiJavaGenerateClient")
}

sourceSets {
    main {
        java {
            srcDir(layout.buildDirectory.dir("generated/sources/openApiServer/java/main"))
            srcDir(layout.buildDirectory.dir("generated/sources/openApiClient/java/main"))
        }
    }
}
While not strictly necessary, you can also add a
doLast
block to the original task that deletes unneeded files:
Copy code
doLast {
        val outputDir = layout.buildDirectory.dir("generated/sources/openApiClient").get().asFile
        for (file in outputDir.listFiles()) {
            if (file.name != "java") {
                file.deleteRecursively()
            }
        }
    }
I've confirmed that this works and the strange behavior in IntelliJ goes away. So now that we have the bad way of doing this, here's my question: what's the good way?
A more elegant solution I've found is to generate the files in a tmp dir and only copy
java/main
from the tmp dir into `generated/sources`:
Copy code
// Copy only "java/main" from the tmp dirs into "generated/sources".
tasks.register<Copy>("openApiJavaGenerateServer") {
    group = "OpenAPI Java"
    description = "Generates JAX-RS server interfaces from the OpenAPI YAML."

    dependsOn(tasks.named("openApiJavaGenerateServerTmp"))
    from(layout.buildDirectory.dir("tmp/openApiServer/java/main"))
    into(layout.buildDirectory.dir("generated/sources/openApiServer/java/main"))
}

tasks.register<Copy>("openApiJavaGenerateClient") {
    group = "OpenAPI Java"
    description = "Generates Retrofit clients from the OpenAPI YAML."

    dependsOn(tasks.named("openApiJavaGenerateClientTmp"))
    from(layout.buildDirectory.dir("tmp/openApiClient/java/main"))
    into(layout.buildDirectory.dir("generated/sources/openApiClient/java/main"))
}

// Compile the Java sources that are generated from the OpenAPI YAML.
sourceSets {
    main {
        java {
            srcDir(tasks.named("openApiJavaGenerateServer"))
            srcDir(tasks.named("openApiJavaGenerateClient"))
        }
    }
}
v
You can disable almost all files and make the code generated in the root output directory. That is how I used the open API generation plugin. I think I detailed it here or on the forums some while ago, so search in the forums and linen. To do it without that, you would probably need something like
srcDir(openApiGenerate.map { it.targetDirectory.dir("java/main") }
or something similar, depending on the properties available.
m
Do you by chance know what you put in
.openapi-generator-ignore
? For one of my tasks, I need all the Java sources that are generated as part of the supporting files, but all other supporting files should be suppressed. At that point, it should be a simple as tweaking
outputDir
and
sourceFolder
v
Have to remember what project that was and then check
m
ACK. Also, in a
buildSrc
plugin, what's the correct way to reference a file in
buildSrc/src/main/resources
(as opposed to
src/main/resources
for the project that consumes the plugin)?
v
Get it as resource from a
Class
or
Classloader
like in any other Java project.
m
It ends up being a little trickier than that, because it's a file in a JAR. It may be best to add a
doFirst
to the task that creates the file.
Copy code
doFirst {
        val ignorePath = "generated/sources/openApiClient/java/main/.openapi-generator-ignore"
        val ignoreFile = layout.buildDirectory.file(ignorePath).get().asFile
        ignoreFile.parentFile.mkdirs()
        val contents = "" // TODO
        ignoreFile.writeText(contents)
    }
This works:
Copy code
val contents = listOf(
            "/*",
            "**/*",
            "!**/*.java",
        ).joinToString("\n")
How ignore files exactly combine inclusions and exclusions is a bit of a mystery. I tried other options that looked like they would work, but didn't work.
v
Do you by chance know what you put in
.openapi-generator-ignore
?
Copy code
/build/generated/sources/openapi/main/java/**
!build/generated/sources/openapi/main/java/org/**
With
layout.buildDirectory.dir("generated/sources/openapi/main/java")
as output dir, the three packages set to
org....
and the
sourceFolder
set to an empty string. The ignore file is directly in the project root and configured via
ignoreFileOverride
which is additionally added as input file due to #10214.
It ends up being a little trickier than that, because it's a file in a JAR.
How does that make any difference? If it is a file on the classpath, get it as resource from class or class loader, no matter whether it is a file on disk or a jar, that does not matter at all.
But yeah, you can of course also generate the file instead of copying it from the classpath.
Oh, you meant directly using the file as ignore file I guess. Yeah, this is only possible if the consumer accepts a file URL. If it needs a File, you either need to copy the file from the classpath to some local file for example in some other task, or use for example
resources.text.fromUri("...").asFile()
to get it as actual file, or of course generate it.