Use case
I want to download arbitrary files during build execution because not all of my build dependencies are available in a structured repository and I also need to setup some tools in the project for development.
As some of those files are large I want Gradle to cache them outside of the project directory so they don’t have to be re-downloaded.
Proposed solution
I can set up an Ivy repository with a custom pattern so Gradle downloads my files using it’s dependency resolution and caching while ignoring the missing Ivy metadata. As I don’t want to clutter my repository configuration with many fake repositories that slow down my build I came up with a solution that temporarily overwrites the repository configuration.
/**
* Downloads the specified file using Gradle's resolution and caching strategy.
*
* Note that this method resolves and downloads the file immediately. Avoid calling this during configuration phase,
* e.g. by wrapping it into a closure.
*
* Implementation notes:
* This configures a custom Ivy repository for the supplied URL and temporarily replaces the existing project repositories.
*
* @param downloadUrl the URL of the file to download
* @param changing specifies if up-to-date checks should be performed; set this to false if you are sure that the file never changes
* @return the downloaded and cached file
*/
File downloadDependency(String downloadUrl, boolean changing = true) {
logger.info("Resolving custom dependency: {}", downloadUrl)
URL u = new URL(downloadUrl)
String group = u.getHost().split('\\.').reverse().join('.')
String name = u.getFile()
Dependency dependency = dependencies.create([group: group, name: name])
dependency.changing = changing
Configuration configuration = project.configurations.detachedConfiguration(dependency)
configuration.transitive = false
configuration.resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
List<ArtifactRepository> savedRepositories = new ArrayList<>()
savedRepositories.addAll(project.repositories)
try {
project.repositories.clear()
project.repositories.ivy {
url "${u.protocol}://${u.host}"
layout 'pattern', {
artifact '[artifact]'
ivy 'ignore-ivy-file.xml'
}
}
return configuration.resolve().iterator().next()
} finally {
project.repositories.clear()
project.repositories.addAll(savedRepositories)
}
}
Questions
- Is it safe to temporarily overwrite the configured repositories? Could there be any side-effects?
- Are there better solutions to my problem?