How to copy Gradle caches to another offline machine?

I’ve got two Ubuntu 16.04 machines. One is connected to the Intenet, while the other one is fully offline. I’d like to build an Android project on the offline machine. On the online machine, it builds successfully. So, I’ve copied whole .gradle to the offline machine and run build process with --offline flag. Surprisingly it fails: Lots of

No cached version of .... 

I suspect it’s because of the hash algorithm used to generate hash for each .jar, .pom, etc. I think hashes are different from one to another machine. Also note that my username and machine name is different in this two. It looks like hashes are related to the username. Am I right? Is there a clean solution to get the project built on the offline machine?

  • Gradle 4.0-bin
  • com.android.tools.build 2.3.0
1 Like

The cache is specifically not portable due to absolute file references. If your user name is different, your ~/.gradle is likely in a different location, which will break the cache. Rather than rely on the implementation details of the cache, it would be better to work at higher level.

One way you could do this is to gather all of your dependencies in an archive. For example, something like this should grab everything in all configurations:

task bundleDependencies(type: Tar) {
    baseName = 'dependencies'
    configurations.each { configuration ->
        if (configuration.canBeResolved) { from configuration }
    }
}

Transfer the archive to the offline machine, extract, and use a flatDir repository (maybe conditionally if you want to use it when offline without adding it each time):

repositories {
    if (gradle.startParamter.offline) {
        flatDir { dirs 'path/to/extracted/dependencies/tar' }
    }
}

You shouldn’t have to change anything else in your build.

4 Likes

How does this change for a multi project build? I can get it to do an archive for each subproject but 1 big combined one would be better

Think I have something working now

task buildOfflineRepo(type: Tar) {
    archiveBaseName = 'offlineRepo'
    destinationDirectory = file(project.projectDir)
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    subprojects {
        configurations.each { configuration ->
            if (configuration.canBeResolved) { from configuration }
        }
    }
}

Tarring up the configurations won’t get you all the pom.xml’s used in dependency resolution (including parent POMs and BOMs). For this reason I wrote a dependency export plugin.

The plugin exports to a folder using the Maven directory layout conventions so the folder can be used as a maven repository.

1 Like