SBT Fails To See Local Maven Repository

scala

Introduction

In this article, we will discuss how to make Scala Build Tool (SBT) fetch dependencies from a local maven repository. On windows, the repo is normally located at C:/Users/username/.m2 directory. This post is inspired by a question posted on stackoverflow.

It will be helpful to anyone who is running a container in docker on windows and needs to supply dependencies available in their local maven repository on the host machine to the container.

Background

This is my first time to work with SBT and I was frustrated for sometime by SBT’s failure to download some dependencies from common and very reliable repositories such as Sonatype and Apache.

Sometimes SBT would report the dependencies as not found and other times as failed to download, all of which lead to the container failing to run.

Solution

Add Artifacts to Local Maven Repo

When we realize that SBT is failing to get dependencies from different sites, we can note down the failed downloads and ensure that we add these to the local maven repo. Get the official tutorial for adding a jar/artifact to local repo by following this link.

Add a Resolver

We then add an SBT resolver for local maven repo in the build.sbt and /project/plugins.sbt. This can be done in a number of ways:


resolvers+=Resolver.mavenLocal

or:


resolvers+="Local Maven Repository" at "file://"+Path.userHome+"/.m2/repository"

or better still:


resolvers+="Local Maven Repository" at Path.userHome.asFile.toURI.toURL + ".m2/repository"

SBT resolves all these paths to /root/.m2/repository, atleast on a windows 8.1 and docker version 1.12.0 host it did.

Get Resolution Path

We can find out exactly where SBT looks for local maven artifacts in your case after adding one of the above resolvers. When a dependency resolution fails during run:


docker run -p 9000:9000 egima/play activator run

check the logs, in my case it was something like:


==== Maven2 Local: tried
file:/root/.m2/repository/org/sonatype/sisu/sisu-guice/3.1.0/sisu-guice-3.1.0.jar
==== Apache Repository: tried https://repository.apache.org/content/repositories/releases/org/sonatype/sisu/sisu-guice/3.1.0/sisu-guice-3.1.0.jar[0m
::::::::::::::::::::::::::::::::::::::::::::::
:: FAILED DOWNLOADS ::
:: ^ see resolution messages for details ^ ::
::::::::::::::::::::::::::::::::::::::::::::::
:: org.sonatype.sisu#sisu-guice;3.1.0!sisu-guice.jar
::::::::::::::::::::::::::::::::::::::::::::::

The path after Maven2 Local: tried statement is what we are looking for.

Mount Volume To Container Path

In Docker, what the above error means is that the path resolved by SBT is not being seen and the directory does not exist according to the container.

Inside Docker’s VM, we have access to a shared path on the host machine i.e. C:/Users/user and we can access all files in that path from the VM as /c/Users/user. But a container does not share this path.

We have to explicitely mount this path to the path the docker container considers as $MAVEN_HOME. There are several approaches to mount  a volume to docker container, but in this article, we will take the easiest which involves adding a flag in the run command.

Since we now know MAVEN_HOME as seen by both the docker container and our host machine, we can use the -v flag in the earlier seen run command:


docker run -v /c/Users/me/.m2:/root/.m2 -p 9000:9000 egima/play activator run

This will guarantee that SBT finds all our local maven artifacts and even if it fails in downloading them for whatever reason, we can simply add the required dependencies locally and point SBT to them.

Conclusion

In this post, we looked at how to enable SBT to check our local maven repository for missing dependencies.