Add file to compiled jar and use as a "project" dependency?

Hi,

I have a project (ProjectB) wich depends on another project (ProjectA).

In ProjectB I have a defined the dependency like so:

api(project(":projectA"))

The problem however is that in ProjectA I’m generating a file that uses the built jar for that project (in build/libs/). I wan’t this file to be available in ProjectB. My idea was to just append the file in the jar after it has been created like so:

tasks.register("appendJarWithNative") { 
       dependsOn(createArtifactTask)
       doLast {
            val inputJar = tasks.jar.outputs.files.singleFile
            appendZipFile(inputJar, createArtifactTask.get().output.files.singleFile)
        }
}

But this, do not work. Souces seems to come from the projects “out” directory and not the jar when using project dependency.

Does anybody have any idea how to do this?

Never ever even think of trying to manipulate the outputs of another task.
Neither should multiple tasks share the same output directory.
All that and more disturbs essential performance features like up-to-date checks, build output caching and so on.
Instead configure the tasks properly to right away do the right thing.
In your case for example like this:

val createArtifactTask by tasks.registering {
    val output = layout.buildDirectory.dir("foo")
    outputs.dir(output)
    doLast {
        output.get().file("foo.txt").asFile.writeText("FOO")
    }
}

sourceSets {
    main {
        resources {
            srcDir(createArtifactTask)
        }
    }
}

That will also not only enhance the JAR contents, but also provide the file in question including implied task dependency for any other way the resources are accessed like with a project dependency.

As another general rule of thumb, whenever you use dependsOn (except for witing lifecycle tasks which only existence reason is to trigger other tasks like check, build, or assemble) you are doing something wrong and should instead model proper implicit task dependencies.
Also see here for more details: Cédric Champeau's blog: A Gradle quickie: properly using dependsOn

Thanks for the tip! I’m not very skilled with gradle…

The problem with this solution is that it introduces a circular dependency.

Before I can create the artifact I need to have a “fatJar/uberJar” created. This fat jar is then analysed in an external process which produces an “artifact”. I then want to add back this artifact into the fatJar:

: createArtifactTask
     \--- :produceArtifact
          \--- :buildDockerImage
               \--- :copyDockerfile
                    \--- :uberJar
                         \--- :classes
                              \--- :processResources
                                   \--- :createArtifactTask (*)

Well, imho that you build a fat jar per-se is an anti-pattern already, but that’s a different topic.

What might work is this instead:

  • Have an additional task that produces a new jar file instead of manipulating the output of the other task
  • Add a feature variant for that enriched fat jar
  • Depend on that feature variant from B