Age Mooij
Age Mooij

Reputation: 824

SBT: Can I dynamically add a library dependency based on another one?

I'm trying to build a plugin that adds a runtime dependency on a specific library (the aspectj weaver JVM agent) if the project libraryDependencies contains one of a certain set of other libraries (one of the Kamon libraries that needs runtime aspectj weaving) so that I can then reference that downloaded dependency file when creating a Docker image (using sbt-docker).

Kamon specifies the aspectj weaver as a "provided" dependency but AFAICT those are not transitively available from projects that depend on one of those Kamon libs.

The problem is that I can't override libraryDependencies in my plugin because at that time the actual project hasn't yet added any dependencies, so I get an empty list. So I have to somehow add this dependency after the project has had its libraryDependencies set but before SBT starts downloading dependencies.

Is this possible? Is there another setting that I can override to achieve this?

My backup is to somehow download that aspectj jar myself from the task in my plugin. Is there some SBT subsystem that I could use for that so that the jar file gets resolved against (or downloaded to) the local Ivy repo?

Upvotes: 4

Views: 862

Answers (1)

Age Mooij
Age Mooij

Reputation: 824

I figured it out using allDependencies. Here's the (abbreviated) code:

object AspectjWeaverPlugin extends AutoPlugin {
  private val aspectjWeaver = "org.aspectj" % "aspectjweaver" % "1.8.5" % "runtime"
  private val aspectjWeaverLibs = List("kamon-spray", "kamon-akka", "kamon-scala")

  val aspectjWeaverJarFile = taskKey[Option[File]]("The aspectj weaver jar file if it exists on the classpath.")

  override def requires = plugins.JvmPlugin
  override def projectSettings = Seq(
    allDependencies := {
      allDependencies.value ++ libraryDependencies.value.find(module => aspectjWeaverLibs.contains(module.name)).map(_ => aspectjWeaver)
    },
    aspectjWeaverJarFile := {
      val classpath = (managedClasspath in Runtime).value

      classpath.find(_.data.getName == s"${aspectjWeaver.name}-${aspectjWeaver.revision}.jar").map(_.data)
    }
  )
}

Now I can use that new task with the optional aspectj weaver jar file in it to set the necessary -javaagent:... option on run, re-start, and in the Docker image I produce with sbt-docker.

Still curious whether this is the best way to do it though.

Upvotes: 3

Related Questions