Save external dependencies to lib folder to build offline

I’m a newbie with gradle. Can someone help?

MAIN IDEA I want to save my external dependencies to a lib folder, in order to build a project offline and without some gradle cache information. The lib folder is part of the project and will be commit to the repository.

If an other user checkout the project he can build this project without internet connections.

ISSUES I try to write a task which copy project dependencies to folder according the maven repoistory folder layout.

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;
  apply plugin: 'java'
  repositories {
 // if offline use local repo...
 maven {
url uri('/tmp/foo/lib/')
}
    // intial use this repo...
 mavenCentral()
}
  dependencies {
 testCompile group: 'junit', name: 'junit', version: '4.1'
 testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5'
}
  task copyToLib() {
 configurations.testCompile.copy().allDependencies.each {dep ->
  String jarFileName = dep.name + "-" + dep.version + ".jar"
  String directory =
"/tmp/foo/lib/" + dep.group + "/" + dep.name + "/" + dep.version + "/";
  String jarFilePath = directory + jarFileName
    if(!new File(jarFilePath).exists()){
   new File(directory).mkdirs();
   configurations.testCompile.each { File path ->
    if (path.name.equals(jarFileName)) {
     String newJarFilePath = directory + path.name
     Files.copy(path.toPath(), FileSystems.getDefault().getPath(newJarFilePath));
    }
   }
  }
 }
 }
  jar.dependsOn('copyToLib')

is there a better way to resolve my requirement. If not, how can i resolve the transitive dependencies to store it in a maven repository directory layout?

Maybe this will work for you

ext {
  File offlineTestCompile = new File('/path/to/wherever/you/want')
}
  task copyToLib( type: Copy) {
  from configurations.testCompile.files
  into
offlineTestCompile
}

In order to access when offline:

dependencies {
  if(gradle.startParameter.isOffline()) {
    testCompile fileTree( dir: offlineTestCompile, include '*.jar' )
  } else {
    testCompile group: 'junit', name: 'junit', version: '4.1'
    testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5'
    }
}

Thanks Cronjé, according your input i adjust my script, seems to work…

apply plugin: 'java'
  def developmentMode = true // TODO: pass as gradle argument...
def lib = "/tmp/lib"
def compileLib = "/tmp/lib/compile"
def runtimeLib = "/tmp/lib/runtime"
def testCompileLib = "/tmp/lib/testCompile"
def testRuntimLib = "/tmp/lib/testRuntime"
  repositories {
 mavenCentral()
}
  dependencies {
 if(!developmentMode){
  compile fileTree( dir: compileLib )
  runtime fileTree( dir: runtimeLib )
  testCompile fileTree( dir: testCompileLib)
  testRuntime fileTree( dir: testRuntimLib )
 }
 else {
  compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5'
  testCompile group: 'junit', name: 'junit', version: '4.1'
 }
}
  task deleteLib(type: Delete) {
  onlyIf {developmentMode}
 delete lib
}
  task copyCompileToLib(type: Copy) {
 outputs.upToDateWhen {false}
 onlyIf {developmentMode}
 from configurations.compile.files
 into compileLib
}
  task copyRuntimeToLib(type: Copy) {
 outputs.upToDateWhen {false}
 onlyIf {developmentMode}
 from configurations.runtime.files
 into runtimeLib
}
  task copyTestCompileToLib(type: Copy) {
 outputs.upToDateWhen {false}
 onlyIf {developmentMode}
 from configurations.testCompile.files
 into testCompileLib
}
  task copyTestRuntimeToLib(type: Copy) {
 outputs.upToDateWhen {false}
 onlyIf {developmentMode}
    from configurations.testRuntime.files
 into testRuntimLib
}
  task copyToLib() {
 onlyIf {developmentMode}
 dependsOn copyCompileToLib, copyRuntimeToLib, copyTestCompileToLib, copyTestRuntimeToLib;
}
  copyCompileToLib.dependsOn deleteLib
copyRuntimeToLib.dependsOn deleteLib
copyTestCompileToLib.dependsOn deleteLib
copyTestRuntimeToLib.dependsOn deleteLib
compileJava.dependsOn copyToLib

…but, the build is not declarative and readable anymore…according to my understanding, this logic should be mapped to a gradle plugin…i will learn how to write a plugin and post my solution. :slight_smile:

You can hide a lot of the complexity in a separate gradle script. If you create a ‘foo.gradle’ file in the ‘gradle’ subdirectory, you can include it via

apply from: 'gradle/foo.gradle'
1 Like

You can also probably shorten a lot of your code by doing something like

task copyToLib << {
  [ 'compile','runtime','testCompile' ].each { mode ->
    copy {
      from configurations.getByName(mode).files
      into ext."${mode}Lib"
    }
  }
}

That should eliminate most of the Copy tasks you have created. If you read up on the ‘Copy’ task (or the equivalent ‘project.copy’ which I used, you can probably make your copying even a bit smarter.

I would also suggest you only run the task manually when needed, not everytime you run gradle.

Always use a ‘Copy’ task over the ‘project.copy’ method, unless there is a very specific reason not to. A ‘Copy’ task can have arbitrary many from-into pairs (e.g ‘into(“bar”) { from “foo” }’), in addition to the (mandatory) top-level ‘into’.

Why all the ‘outputs.upToDateWhen {false}’?

I noticed while testing that some tasks has not been exectued. I’m not sure buti also when i change the project dependencies the tasks has not been executed…