What do @IgnoreEmptyDirectories and @NormalizeLineEndings do on a task input, and what kinds of false cache misses do they prevent?
answer
- false cache miss = irrelevant input change
- empty dirs busting fingerprint
- CRLF vs LF portability
- both layer on @PathSensitive
- only loosen when tool ignores it too
basics
~10 s@IgnoreEmptyDirectories drops empty directories from the input fingerprint so they don't trigger reruns. @NormalizeLineEndings hashes text files ignoring CRLF vs LF differences, so a line-ending-only change doesn't bust the cache.
solid answer
~40 sBoth annotations refine how a file input is fingerprinted to eliminate *false* cache misses — changes that shouldn't logically affect the output. `@IgnoreEmptyDirectories` (on `@InputFiles`/`@InputDirectory`) tells Gradle not to include empty directories in the fingerprint; otherwise an empty `build/tmp` or a directory left behind by a checkout would change the input hash even though no real file changed. `@NormalizeLineEndings` makes Gradle fingerprint text-file content after normalizing line endings, so the same source checked out on Windows (CRLF) and Linux (LF) produces identical fingerprints and a portable cache hit. Both are opt-in refinements layered on top of `@PathSensitive`; you add them when the underlying tool genuinely ignores those differences, gaining more up-to-date and shared-cache hits without changing build correctness.
code
kotlin · 5 lines@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
@get:NormalizeLineEndings
@get:IgnoreEmptyDirectories
abstract val sources: ConfigurableFileCollectiongo deeper
Know these two annotations exist to avoid needless re-runs from empty folders and line-ending differences.
Explain how each prevents false cache misses and that they layer onto @PathSensitive without changing on-disk files.
Reason about correctness limits — when ignoring empty dirs or normalizing line endings would actually be wrong for the tool.
Standardize these on cross-platform inputs in convention plugins to keep a heterogeneous (Windows + Linux) remote cache effective.
## False cache misses A *false* cache miss is when Gradle re-runs a task (or misses the build cache) because an input fingerprint changed in a way the actual tool doesn't care about. Two common sources are empty directories and line-ending differences. Gradle provides annotations to normalize them away. ## @IgnoreEmptyDirectories By default an input directory tree's fingerprint includes the directory entries themselves, including empty ones. So if a VCS checkout, a previous task, or the OS leaves an empty folder inside the input, the fingerprint differs and the task re-runs even though no file content changed. Annotating the input with `@IgnoreEmptyDirectories` excludes empty directories from the fingerprint. Use it when only files matter to the tool (most code/resource processing). The inverse default (`@IgnoreEmptyDirectories(false)` semantics) keeps them, which matters only when an empty directory is itself meaningful output/input. ## @NormalizeLineEndings Text files committed by different developers or different OSes may use `\r\n` (CRLF) or `\n` (LF). Without normalization those byte differences change the content hash. `@NormalizeLineEndings` makes Gradle normalize line endings before hashing **text** files, so the logical content drives the fingerprint. This is what lets a Windows checkout and a Linux CI agent share a remote cache entry. It applies to inputs declared with content-based fingerprinting. ## How they combine These are additive refinements, applied alongside path sensitivity: ```kotlin abstract class ProcessText : DefaultTask() { @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) @get:IgnoreEmptyDirectories @get:NormalizeLineEndings abstract val sources: ConfigurableFileCollection @get:OutputDirectory abstract val out: DirectoryProperty } ``` ## When NOT to use them Don't normalize line endings if the tool's output actually depends on exact bytes (e.g. you compute a checksum of the raw file). Don't ignore empty directories if an empty directory is a meaningful signal the task reacts to. The guiding principle is the same as path sensitivity: loosen the fingerprint only when it stays *correct*.
- Why does @NormalizeLineEndings matter specifically for a shared remote build cache?Developers and CI agents on different OSes check out text files with different line endings. Without normalization, byte-level CRLF/LF differences change the content hash and prevent the Windows and Linux runs from sharing the same cache entry.
- Could @IgnoreEmptyDirectories ever cause an incorrect result?Yes, in the rare case where an empty directory itself is a meaningful input/output the tool reacts to. Then ignoring it would make Gradle wrongly consider the task up-to-date.
saying these in an interview costs you the question
- Saying @NormalizeLineEndings reformats the actual files — it only affects fingerprinting, not file content on disk.
- Claiming these replace @PathSensitive — they are additive refinements, not substitutes.
- Assuming line-ending normalization applies to binary files — it targets text files.