Rohit Rohit - 3 months ago 27
Scala Question

Is there anyway to prepend a jar to the unmanagedClasspath in sbt

I am using the

android-sbt-plugin
with the sbt, and I would like to add an unmanaged jar to the test classpath. The reason being android.jar contains stub functions for the org.json libraries and results in exceptions being thrown for unit tests. This is what I am doing

unmanagedClasspath in Test <+= (baseDirectory) map { base =>
Attributed.blank(base/"test-libs"/"json.jar")
}


Because of the order of the jars this file is ignored during when i run the test command within the sbt. If I type the command the order clearly shows the android.jar as the first jar


show test:unmanaged-classpath
[info] ArrayBuffer(Attributed(/home/rohit/Projects/android-sdk-linux/platforms/android- 17/android.jar), Attributed(/home/rohit/Projects/barfrendz/trunk/src/buzze/test-libs/json.jar))


If I create a lib folder and let sbt pick up the json jar the order is reversed the tests now run, but I can no longer create an android package due to conflicts with the org.json namespace in android.jar. Here is the exception

[error] (Buzze/android:proguard) java.io.IOException: Can't read [/home/rohit/Projects/barfrendz/trunk/src/buzze/lib/json.jar(;;;;!META-INF/MANIFEST.MF,!**/R.class,!**/R$*.class,!**/TR.class,!**/TR$.class,!**/library.properties)] (Can't process class [org/json/CDL.class] (Unsupported version number [51.0] for class format))


Is there anyway I can change the order of the jars in the classpath for the unit tests?

Answer

Instead of using <+=, use <<=, get unmanagedClasspath itself as a dependency, and then modify it as desired. The documentation has such an example with resolvers:

resolvers <<= resolvers {rs =>
  val localMaven = "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository"
  localMaven +: rs
}

This way, localMaven ends up first in resolvers.

According to the API docs, the unmanagedClasspath is a Task of type Classpath. Note that when you use that syntax, you are changing the Classpath, not the Task.

The API doc for the classpath is here -- it's a type, and it points to Seq[Attributed[File]], so you can manipulate it with any Seq command. I tried out the snippet here and it works:

$ cat build.sbt
unmanagedClasspath in Test <<= (unmanagedClasspath in Test, baseDirectory) map { (uc, base) =>
    Attributed.blank(base/"test-libs"/"json.jar") +: uc
}

Daniel@DANIEL-PC /c/scala/Programas/sbtTest
$ sbt
[info] Set current project to default-60c6f9 (in build file:/C:/scala/Programas/sbtTest/)
> show test:unmanaged-classpath
[info] ArrayBuffer(Attributed(C:\scala\Programas\sbtTest\test-libs\json.jar))
[success] Total time: 0 s, completed 30/08/2013 13:32:42
>