Hi, Is it possible to find out which files in the ...
# community-support
m
Hi, Is it possible to find out which files in the output of a sourceSet are stale, so they can be ignored or deleted? After switching branches and compiling, the class files from the old branch are still there, even if the source is not, and they are added to the jar, if forbidden-apis does not choke on the file. Incremental compile does not seem to make a difference, forcing
classes
to run does not cause it to remove the stale class in either case.
1
m
This sounds like a problem of the
classes
tasks? If incremental, it should delete the stale files. If not, it should delete the destination content before writing the new one
m
That would be easiest, yes. Do you mean this should already be the case that
classes
does this (which might point to some error in my build), or is that more of a wish that it should do that?
m
I would naively expect this indeed.
When writing a task that generate sources, I always delete the whole output directory first thing before re-generating the new source files
But then maybe
classes
has some extra logic. Is that from a Java project?
If it is java, shouldn't it be
compileJava
?
m
It is java. I'll try to get a minimal reproducer, to rule out my own setup
m
Copy code
name: :classes
type: class org.gradle.api.DefaultTask
inputProperties:
 - 
inputsFiles:
 - 
sourcefiles:
 - 
outputs:
 - 
dependencies:
 - :compileJava
 - :processResources
So
classes
looks like it's a lifecycle task
Just tried locally to remove a .java file and call
compileJava
and the matching
.class
file is correctly removed from
build/classes/java
so there is probably something with the seupt
m
I deleted a needed class file, so it should not make a difference which task it really is. Thanks for checking the behaviour, though, I'll try to find where I'm going wrong
Thank you again! This really seems to be related to our build setup, I can see the correct behaviour in a
gradlew init
project. I'll report back what it was when I find it.
👍 1
t
IIRC, Gradle's behavior might change when an output directory is "shared" by multiple tasks (i.e. two tasks configured with the same output directory).
m
Thanks for the hint, I don't think I would have looked for that first, but that sounds quite likely now that you mention it
m
two tasks configured with the same output directory
Are there valid use cases for this? Sounds like Gradle should give an error for this?
m
With
-i
, I don't see any message about overlapping outputs, only that removing a different class file indeed caused a full rebuild:
Copy code
Task ':foo:compileJava' is not up-to-date because:
  Output property 'destinationDirectory' file foo\build\classes\java\main\foo\Bar.class has been removed.
The input changes require a full rebuild for incremental task ':foo:compileJava'.
That did not remove the offending class file, though.
😮 1
m
Could it be a bug from case insensitive filesystem?
Do your 2 files have really different names?
m
Very much so. The stale file had it's own package. Let me give that a try in my reproducer, maybe gradle leaves directories alone, as opposed to files in an existing output package dir.
Nah, that's also cleaned up properly in my reproducer
In my repoducer, I get the following log after switching to the branch without Foobar.java:
Copy code
Task ':lib:compileJava' is not up-to-date because:
  Input property 'stableSources' file Z:\Workspaces\test\lib\src\main\java\org\test\Foobar.java has been removed.
But in my "real" build, I only see that message for a changed file in my conventions build, not for the removed file. In that project, the
compileJava
task claims to be up-to-date. Now I'm a bit scared.
v
that removing a different class file indeed caused a full rebuild:
Yes an incremental task can only be incremental when incremental inputs change. As soon as another input or the output changed, a full rebuild is necessary.
That did not remove the offending class file, though.
But the full rebuild usually should also clean up the outputs. One thing that produces similar situations is if you have build cache enabled and there is a poisoned cache entry or inputs and outputs not declared properly for a task.
m
So, I think I've finally been able to track down the reason for this problem and it's quite the corner case. Thank you all for helping me figure this out by ruling out the more likely suspects! Our build is structured with a small number of included builds configured via
settings.gradle
, because they are an integral part of the build. For simplification, we recently re-integrated one of those into the main build again, without changing the directory structure. So what was previously a subproject in an included build is now a subproject in the main build. The offending file resided in exactly one of those subprojects. First building the old branch with the included build and then a newer branch in the same workspace exhibits the problem. Gradle then considers
previous-compilation-data.bin
invalid, which it would normally use to find out which .class files are needed, and it does not delete anything.
v
Sounds like a bug you should report I guess. With it being quite a corner case maybe it could need some time, but it should probably not be kept around either way.
m