Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ignoring empty directories in task inputs #2463

Closed
lptr opened this issue Jul 13, 2017 · 11 comments
Closed

Allow ignoring empty directories in task inputs #2463

lptr opened this issue Jul 13, 2017 · 11 comments
Labels
a:feature A new functionality
Milestone

Comments

@lptr
Copy link
Member

lptr commented Jul 13, 2017

See e.g. this forum request: https://discuss.gradle.org/t/build-cache-issue-how-to-exclude-empty-directories-from-compile/22820

It would be good to be able to declare that an input property does not care about empty directories but only about files. We already do this automatically for classpath resources.
The use case described in the forum is Java source files which also makes good sense.

@big-guy
Copy link
Member

big-guy commented Jul 13, 2017

I think it could make sense for this to be the default behavior with maybe a way to opt into "directories are meaningful" if there's a use case for it. I think Copy-like tasks are the only ones that are obviously sensitive to directories (but even that's configurable).

As an example, I think we should consider:

src/main/java/com/example/Foo.java
src/main/java/com/example/internal/Bar.java

and

src/main/java/com/example/Foo.java
src/main/java/com/example/internal/Bar.java
src/main/java/com/example/newpackage (empty directory)

as identical. It could be easy for people to get build cache misses without an obvious cause otherwise.

@SUPERCILEX
Copy link
Contributor

@wolfs I'd like to try and fix this, is that ok? I'd be making it so that @Optional allows for both null values and if applied to an @Input[File(s)/Directory], non-extent files.

@SUPERCILEX
Copy link
Contributor

Oh my B, this is the wrong issue. I meant #2016. Either way, I'd like to fix all the input inconsistencies. 😁

@autonomousapps
Copy link
Contributor

Is this issue also about empty source roots? For example, if you have two builds, and in one of those builds an empty root:

module/src/main/java

there will be a cache miss if the task involved has multiple source roots. For example, KotlinCompile. Example build comparison.

@autonomousapps
Copy link
Contributor

I have seen this issue impact users without their having any awareness of it. It is apparently not uncommon to have empty source directories in a project. Because git will not commit an empty directory, only some users will have an empty dir, leading to relocatability issues that impact the remote build cache.

Here is how this situation typically arises, in my experience:

  1. A developer will use the IDE (e.g., Android Studio) to create a new module. The IDE helpfully creates main, test, and androidTest source roots. The latter two will contain template test classes. The developer might delete the template tests but not delete the folders.
  2. A developer will take an existing large module and factor out a submodule, with the idea of improving the ability of gradle to build bits of the project in parallel. This often leaves behind -- completely accidentally -- empty packages.

In either case, git clean -fd will remove these empty directories, but nevertheless people might go months missing out on remote cache hits because they don't think to do this.

Proposal: Gradle ignore empty source directories by default. Is there a use-case for considering them? Do empty directories ever carry semantic meaning?

@autonomousapps
Copy link
Contributor

As an addendum, sometimes people do something like the below to detect empty source dirs and fail the build in their presence. Unfortunately, this has the side effect of making every SourceTask care about the state of the build script itself. Any change to the build script will now cause these tasks to be out of date. We should do our best to make such ugly workaround unnecessary.

// Empty source dirs produce cache misses, and are not caught by 
// `git status`.
// Fail if we find any.
subprojects {
  tasks.withType(SourceTask).configureEach { t ->
    t.doFirst {
      t.source.visit { FileVisitDetails d ->
        if (d.file.directory && d.file.listFiles().size() == 0) {
          throw new IllegalStateException("Empty source dir: " + d.file.absolutePath + "\nRun `git clean -fd`")
        }
      }
    }
  }
}```

@runningcode
Copy link
Member

Yes, this happens quite often. I would estimate that this is happening in every non-trivial project with more than one developer and a version control system.

This can also happen the following case:
3. Move a class (or several classes) from one package to another package within the same module leaving an empty package.

@isker
Copy link
Contributor

isker commented Aug 1, 2019

This is happening to us with great frequency and makes using the build cache correctly a challenge. Configuring custom task inputs with FileTree is a trap for all but the most trivial cases.

If there's no fix for this problem forthcoming, can the documentation be updated to reflect this fact? Can FileTree#getFiles be prominently called out as the correct solution?

@Tapchicoma
Copy link

As temporary workaround if you are using git, you could add following git hook - .git/hooks/post-checkout:

#!/bin/sh
set -e
find . -type d -empty -not -path "./.git/*" -not -path "*/build/*" -not -path "./.idea/*" -not -path "*/.gradle/*" -delete

runningcode added a commit to runningcode/gradle-doctor that referenced this issue Jul 27, 2020
These cause cache misses such as with the `MergeResources` task in the Android Gradle Plugin.

Workaround for Gradle treating empty directories as unique: gradle/gradle#2463
@ZacSweers
Copy link

FYI that Kotlin kapt in 1.4.0 appears to leave empty source directories: https://youtrack.jetbrains.com/issue/KT-41353

runningcode added a commit to runningcode/gradle that referenced this issue Sep 3, 2020
When an empty source directory is found, fail the build. Empty source directories cause cache misses.

Ref gradle#2463
runningcode added a commit to runningcode/gradle that referenced this issue Sep 29, 2020
These cause cache misses and slow down the build. We need to dogfood this issue so we are motivated to fix it.

Follow up from gradle#14407

If you are reading this, please vote this up:
gradle#2463
@wolfs
Copy link
Member

wolfs commented Dec 7, 2020

This has been fixed in 6.8 RC1.

@wolfs wolfs closed this as completed Dec 7, 2020
@wolfs wolfs added this to the 6.8 RC2 milestone Dec 7, 2020
@big-guy big-guy modified the milestones: 6.8 RC2, 6.8 RC1 Dec 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:feature A new functionality
Projects
None yet
Development

No branches or pull requests

9 participants