# Cache inputs resolved from main input file to speed up configure times

**URL:** <https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855>\
**Category:** Help/Discuss\
**Created:** [May 8, 2018, 8:53am UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855 "2018-05-08T08:53:31Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![staffanf](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/staffanf/32/6017_2.png) [@staffanf](https://discuss.gradle.org/u/staffanf)\
**Post date:** [May 8, 2018, 8:53am UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/1 "2018-05-08T08:53:31Z")

</div>

Hi,  
I feel like the problem of caching task inputs resolved from another input file in order to speed up subsequent configure times would a have standard Gradle solution but I have not found any.

This problem can be found in many builds using e.g xml entities/XIncludes or header files.  
In our case it’s a lot of xml entities and parsing these xml files every configure time is expensive and slows down our “nothing to do” time a lot.

I saw [Caching results of @InputFiles method, is it bad?](https://discuss.gradle.org/t/caching-results-of-inputfiles-method-is-it-bad/19578) but in this example, getDependencies() is still always called in configure time which in our case is bad enough.

Is there any good examples on how to avoid expensive inputs calculations on subsequent executions?

My idea for something like this would be:

```gradle
@InputFiles
Collection<File> xsltInputs = new CacheInputs { 
  // Calculate file inputs closure
}

```

CacheInputs would then save the calculated files to ‘/build/tmp/taskName-something’.  
During the next executions’s configure time, if this file exists, read inputs from it and check file modification times for these files. If file times have changes, run closure to calculate new inputs and save these.

But if there was a was a way to use gradle’s own built in task input caching, that would probably be more effective than creating a own cache in /build.

---

<div class="post-metadata">

**Author:** ![Lance](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/lance/32/787_2.png) [@Lance](https://discuss.gradle.org/u/Lance)\
**Post date:** [May 8, 2018, 12:16pm UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/2 "2018-05-08T12:16:20Z")

</div>

You could remove @InputFiles from the `xsltInputs` and use a custom method. Eg

```gradle
FileCollection xslts;

@InputFiles 
FileCollection createHashes() {
    // create file(s) under $buildDir based on xslts
}

```

---

<div class="post-metadata">

**Author:** ![staffanf](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/staffanf/32/6017_2.png) [@staffanf](https://discuss.gradle.org/u/staffanf)\
**Post date:** [May 9, 2018, 6:56am UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/3 "2018-05-09T06:56:02Z")

</div>

Yes I could, but the idea of assigning the CacheInputs would be that this class could contain all the caching logic and be reusable and the closure would be supplied based on how to extract dependencies from some srcFiles.  
I’m experimenting a little bit and will post a tested prototype when I’m done.

---

<div class="post-metadata">

**Author:** ![Lance](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/lance/32/787_2.png) [@Lance](https://discuss.gradle.org/u/Lance)\
**Post date:** [May 9, 2018, 8:39am UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/4 "2018-05-09T08:39:49Z")

</div>

You could do it like

```gradle
FileCollection xslts 

@InputFiles 
FileCollection xsltHashes = new CustomFileHash(this) {
   createHashes(xslts)
}

```

```gradle
public CustomFileHash implements FileCollection {
    private FileCollection fileCollection
    private final Task task
    private final Closure closure 
    public CustomFileHash(Task task, Closure closure) {
        this.task = task
        this.closure = closure 
    }
    protected FileCollection lazyInitFileCollection() {
        if(fileCollection == null) {
           fileCollection = task.project.files(closure)
         }
         return fileCollection
    }
    @Override
    Set<File> getFiles() {
        return lazyInitFileCollection().getFiles() 
    }
    // todo implement other FileCollection methods
} 

```

---

<div class="post-metadata">

**Author:** ![Stefan\_Wolf](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/stefan_wolf/32/5519_2.png) [@Stefan\_Wolf](https://discuss.gradle.org/u/Stefan_Wolf)\
**Post date:** [May 15, 2018, 4:11pm UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/5 "2018-05-15T16:11:59Z")

</div>

Hi @staffanf,

if you don’t use `Collection<File>` but `FileCollection`, things become a little bit easier. You can still create your `CacheInputs` class which takes a closure. But then you would wrap that class into a `FileCollection` by using `project.files()`. If the result of `CacheInputs` implements `Callable`, then the `Callable` itself would be evaluated as late as possible.

Another option could be to split off a separate task which calculates the inputs. This task would have the original `xml` file as an input and would create a file containing all the “real” input files. The current task would then read that file and declare the contents as input files. This way both tasks can use Gradle’s incremental build infrastructure. You could even share the analysis via the build cache, if you manage to keep the information relocatable (i.e. using a relative path). We did something similar for some times to detect headers for native compilation.

Currently, we use a [`CalculatedInputFileCollection`](https://github.com/gradle/gradle/blob/272848cd65f76a0c4dcbb7b9562227ff2da81395/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/incremental/DefaultIncrementalCompilerBuilder.java#L86) for the header dependencies. Note that this is still internal API, so I would not suggest you use it in your plugin, but it should give you some ideas how to achieve what you want to achieve.

Cheers,  
Stefan

---

<div class="post-metadata">

**Author:** ![staffanf](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/staffanf/32/6017_2.png) [@staffanf](https://discuss.gradle.org/u/staffanf)\
**Post date:** [May 16, 2018, 9:27pm UTC](https://discuss.gradle.org/t/cache-inputs-resolved-from-main-input-file-to-speed-up-configure-times/26855/6 "2018-05-16T21:27:49Z")

</div>

Hi @Stefan_Wolf Thanks for the reply and good feedback.  
I went back and tried to do the simplest possible working xslt task.  
My current implementation was incremental and parallel and this combined with tracking calculated inputs made me take a step back and remove the incremental stuff for now.

I landed in something like this right now:

```gradle
  @InputFiles
  FileCollection calculatedInputs = project.files(new CalculatedInput())

  class CalculatedInput implements Callable<Collection<File>> {

    @Override
    Collection<File> call() throws Exception {
      // Do inputs calculation
    }
    
  }

```

But see this method is getting called at least once in configure() and then just before the task executes.  
I’m curious if there’s info about when/why task inputs are evaluated in configure().

I’m thinking I have a case where I wan’t to cache these inputs the first time the method is called but I can’t be really sure that they are correct since the input file might not exists until just before the task executes. The inputs might be generated by a previous transformation.

But I guess if I would save a cache during execution with file mod times. If these where not changed, then the same inputs could be used again.

CalculatedInputFileCollection would be interesting but I guess it needs some work before it will be an public api.

Question:  
I guess org.gradle.PersistentCache\<\> isn’t something that will be public anytime soon? It seems that might be useful in this kinda case… Although it would open up a lot of possibilities for errors.
