[GRADLE-1885] Jar task should not create build/tmp/x directory when it's not executed Created: 02/Nov/11  Updated: 04/Jan/13  Resolved: 06/Dec/11

Status: Resolved
Project: Gradle
Affects Version/s: 1.0-milestone-3
Fix Version/s: 1.0-milestone-7

Type: Bug
Reporter: Matias Bjarland Assignee: Luke Daley
Resolution: Fixed Votes: 0


Given the following build.gradle in an empty directory:

  task bar(type: Jar) {
    from "somewhere"
    into "somewhereelse"

and the following gradle execution:

command line
 $ gradle tasks

we get the following resulting directory structure:

$ tree
├── build
│   └── tmp
│       └── bar
└── build.gradle

3 directories, 1 file

note that we started from an empty directory.

Digging into the gradle source a bit we find the following code:

//Jar.groovy in gradle source
public class Jar extends Zip {
    Jar() {
        extension = DEFAULT_EXTENSION
        manifest = new DefaultManifest(project.fileResolver)
        // Add these as separate specs, so they are not affected by the changes to the main spec
        metaInf = copyAction.rootSpec.addFirst().into('META-INF')
        metaInf.addChild().from {
            MapFileTree manifestSource = new MapFileTree(temporaryDir)
            manifestSource.add('MANIFEST.MF') {OutputStream outstr ->
                Manifest manifest = getManifest() ?: new DefaultManifest(null)
                manifest.writeTo(new OutputStreamWriter(outstr))
            return new FileTreeAdapter(manifestSource)
        copyAction.mainSpec.eachFile { FileCopyDetails details ->
            if (details.path.equalsIgnoreCase('META-INF/MANIFEST.MF')) {

note among other things the 'temporaryDir' variable access. This comes from a super class a bunch of inheritance levels up:

    public File getTemporaryDir() {
        File dir = getServices().get(TemporaryFileProvider.class).newTemporaryFile(getName());
        return dir;

notice the 'dir.mkdirs()'. So to summarize: just by instantiating the Jar task class we will create the directory structure described above. This is independent of whether we have elected do disable the jar task entirely, excluded it from the execution graph, added an onlyIf clause etc etc.

Note that we get the same result with the following build file:

apply plugin: 'java'

and just executing 'gradle tasks'.

I think this behavior is unexpected and undesirable. In large multi-project builds where we want to leave directories without sources or resources well alone, this becomes a serious issue.

In addition, creating a clean workaround by selectively deleting the build directory only when it was erroneously created by the jar task is actually non-trivial. How do you figure out if the Jar task erroneously created the directory? And if it did, where do you add the code to remove the directory? jar.doLast doesn't work as (in my specific example) I have disabled the jar task and jar.doLast is therefore not executed. Adding this to assemble.doLast works but gets hairy with the state management to only do this when the jar task did the wrong thing.

As this is really not clean I hesitate to even share this, but perhaps it can help somebody out there. I ended up with the following simplistic workaround:

stupid workaround
  assemble.doLast {
    if (!fileTree(dir: buildDir).find { it.isFile() } ) {
      println "no files present in ${project.path} build dir $buildDir, deleting it"

Can we make all the code after the two first lines in the Jar class constructor get executed on first-run or first-access (of say getMetaInf etc) instead of in the constructor?

Comment by Matias Bjarland [ 07/Nov/11 ]

Verified, still an issue in 1.0-milestone-5

Comment by Luke Daley [ 06/Dec/11 ]

Fixed in m7.


Generated at Wed Jun 30 12:06:59 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.