scalajarsbt

Add sources for unmanaged JARs in SBT


I'm setting up a build.sbt where I need to have a bunch of managed JARs on the classpath. I basically have two large folders containing all of the JARs and then also the source JARs.

myManagedRoot
|- deps
|   |- alib.jar
|   |- blib.jar
|   `- clib.jar
`- sources
    |- alib-sources.jar
    |- blib-sources.jar
    `- clib-sources.jar

In my build.sbt, I've got something like

import sbt.nio.file._

lazy val MyProject= project
  .settings(
    Compile / unmanagedJars ++= FileTreeView.default
      .list((file("myManagedRoot") / "deps").toGlob / "*.jar")
      .collect {
        case (path, attributes) if attributes.isRegularFile => path.toFile
      }
  )

However, I'm not sure where I can thread in the source JARs. I see in SBT that the fetching of those JARs occurs in updateClassifiers, but I'm not sure what the best way is to hook into existing tasks for that.


Solution

  • You can try a custom setting (i.e. calculated once on a project load, on contrary to a custom task calculated every time when executed) decompressing jars with sources

    lazy val unjar = settingKey[Seq[File]]("unjar sources")
    
    lazy val myProject = project
      .settings(
        unjar := {
          (baseDirectory.value / ".." / "sources" ** "*.jar").get.map { file =>
            val dir = baseDirectory.value / ".." / "sources-unjar" / file.name.stripSuffix(".jar")
            IO.unzip(file, dir)
            dir
          }
        },
    
        Compile / unmanagedSourceDirectories ++= unjar.value,
    
        Compile / unmanagedJars ++= (baseDirectory.value / ".." / "deps" ** "*.jar").get,
      )
    

    https://www.scala-sbt.org/1.x/docs/Custom-Settings.html

    Make sure that all directories sources-unjar/alib-sources, sources-unjar/blib-sources, ... are marked as source roots in your IDE.


    Update. You can rename your jars (adding version e.g. 1.0.0) and re-arrange them into the following directory structure:

    directories

    The .pom files are:

    <?xml version='1.0' encoding='UTF-8'?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>alib</artifactId>         <!-- alib, blib, clib, ... -->
        <packaging>jar</packaging>
        <version>1.0.0</version>
    </project>
    

    Then with the following build.sbt your dependencies should be found (both classes and sources):

    lazy val myProject = project
      .settings(
        resolvers += MavenCache("local-maven", baseDirectory.value / "deps"),
        libraryDependencies ++= Seq(
          "com.example" % "alib" % "1.0.0",
          "com.example" % "blib" % "1.0.0",
          "com.example" % "clib" % "1.0.0",
        )
      )
    

    https://www.scala-sbt.org/1.x/docs/Resolvers.html#Local+Maven+resolvers

    Upon necessity all renamings and re-arrangings can be done programmatically.

    (The easiest would be if you had all projects alib etc. locally. Then you could do sbt publishLocal for them and use them as ordinary dependencies.)