Walk through the FileChange objects returned by InputChanges.getFileChanges: what does each ChangeType mean and what information does a FileChange carry?
answer
- Iterable<FileChange>
- ChangeType ADDED/MODIFIED/REMOVED
- getFile / normalizedPath / fileType
- rename = REMOVED + ADDED
- filter FileType.DIRECTORY
basics
~10 sgetFileChanges returns an iterable of FileChange. Each has a ChangeType (ADDED, MODIFIED, or REMOVED) and the file plus its normalized path, telling you what happened to that one input file.
solid answer
~40 s`inputChanges.getFileChanges(inputProperty)` returns an `Iterable<FileChange>`. Each `FileChange` describes one input file's change relative to the previous run via `getChangeType()`: **ADDED** (a new input file appeared), **MODIFIED** (an existing input file's content changed), or **REMOVED** (an input file was deleted). A `FileChange` also exposes `getFile()` (the `java.io.File`), `getNormalizedPath()` (path relative to the input root after normalization — stable for computing output locations), and `getFileType()` (`FILE`, `DIRECTORY`, or `MISSING`). You react per type: regenerate outputs for ADDED/MODIFIED, delete the derived output for REMOVED, and usually skip `DIRECTORY` entries. For REMOVED entries the underlying file no longer exists, so rely on `normalizedPath` rather than reading `getFile()`.
code
groovy · 8 linesinputChanges.getFileChanges(inputDir).each { change ->
if (change.fileType == FileType.DIRECTORY) return
def out = outputDir.file(change.normalizedPath).get().asFile
switch (change.changeType) {
case ChangeType.REMOVED: out.delete(); break
default: out.parentFile.mkdirs(); out.text = change.file.text.toUpperCase()
}
}go deeper
Recall the three ChangeType values and that each FileChange names one file.
Describe the FileChange accessors and the rename = REMOVED+ADDED behavior.
Explain normalizedPath's role in deterministic output mapping and DIRECTORY/MISSING handling.
Generally delegated; focus on ensuring teams encode robust per-type handling as a reviewed pattern.
## The shape of the data Calling `getFileChanges(prop)` — where `prop` is one of your `@Incremental` file inputs — yields an `Iterable<org.gradle.work.FileChange>`. Each element answers 'what happened to this one file?'. ### ChangeType - **ADDED** — the file is present now and was not in the previous snapshot. Generate its output. - **MODIFIED** — the file existed before and its (normalized) content changed. Regenerate its output. - **REMOVED** — the file was in the previous snapshot and is gone now. Delete the output it had produced. Its `getFile()` points at a path that no longer exists. Note there is no separate 'renamed' type: a rename surfaces as a REMOVED of the old path plus an ADDED of the new path. ### FileChange accessors - `getFile(): File` — the concrete file (valid for ADDED/MODIFIED; stale for REMOVED). - `getChangeType(): ChangeType` — the enum above. - `getNormalizedPath(): String` — the file's path relative to the input root, after the input's normalization (e.g. `@PathSensitive(RELATIVE)`). Use this to map input -> output deterministically. - `getFileType(): FileType` — `FILE`, `DIRECTORY`, or `MISSING`. Directory entries are often reported when the input is a directory tree; most actions ignore them and act only on `FILE`. ## Typical dispatch ```kotlin changes.getFileChanges(sources).forEach { c -> if (c.fileType == FileType.DIRECTORY) return@forEach val out = outputDir.file(c.normalizedPath + ".out").get().asFile when (c.changeType) { ChangeType.ADDED, ChangeType.MODIFIED -> { out.parentFile.mkdirs(); transform(c.file, out) } ChangeType.REMOVED -> out.delete() } } ``` ## Gotchas - **MISSING file type** can appear for a REMOVED change — don't `readText()` such a file. - **Directory changes**: when you add/remove a whole folder you may get a DIRECTORY-typed change plus per-file changes; filtering on `FileType.FILE` keeps logic simple. - **Renames are two events** — handle REMOVED cleanup so the old output doesn't linger after a rename.
- How does a file rename appear in the change list?As two FileChange entries: a REMOVED for the old path and an ADDED for the new path — there is no dedicated rename type.
- Why prefer normalizedPath over getFile().getPath() for mapping outputs?normalizedPath is relative to the input root and stable across machines/normalization, and it remains meaningful even for REMOVED files whose getFile() is gone.
saying these in an interview costs you the question
- Believing there is a RENAMED ChangeType.
- Calling readText/length on a REMOVED change's file (it may be MISSING).