1

I'm playing around with the scala-forklift library and wanted to test an idea by modifying the code in the library and example project.

This is how the project is structured:

  • /build.sbt -> Contains definition of scala-forklift-slick project (including its dependencies) in the form of:
lazy val slickMigrationProject =
  Project("scala-forklift-slick", file(...))
    .dependsOn(...)
    .settings(...)
    ...

My goal is to replace the scala-forklift-slick Maven package reference with a reference to the code in the parent directory, perhaps via .dependsOn(slickMigrationProject)?

Attempts:

According to the documentation:

Any .sbt files in foo, say foo/build.sbt, will be merged with the build definition for the entire build, but scoped to the hello-foo project.

But this does not seem to apply to lazy val values, as I can't access slickMigrationProject from the parent project directly.

I have been successful copying the entire contents of /example/build.sbt into /build.sbt and tweaking things a bit, but I was wondering if there was a better "one-liner" kind of solution instead. Here is what my combined /build.sbt file looks like:

val repoKind = SettingKey[String]("repo-kind",
  "Maven repository kind (\"snapshots\" or \"releases\")")

lazy val slickVersion = "3.3.3"

lazy val scala212 = "2.12.11"
lazy val scala213 = "2.13.1"
lazy val supportedScalaVersions = List(scala212, scala213)

lazy val coreDependencies = libraryDependencies ++= List(
  "org.scala-lang" % "scala-compiler" % scalaVersion.value,
  "com.typesafe" % "config" % "1.3.2",
  "org.eclipse.jgit" % "org.eclipse.jgit" % "4.0.1.201506240215-r"
)

lazy val slickDependencies = List(
  "com.typesafe.slick" %% "slick" % slickVersion,
  "com.typesafe.slick" %% "slick-codegen" % slickVersion,
  "io.github.nafg" %% "slick-migration-api" % "0.7.0",
  "org.scala-lang.modules" %% "scala-collection-compat" % "2.0.0"
)

lazy val slickDependenciesWithTests = slickDependencies ++ List(
  "org.scalatest" %% "scalatest" % "3.1.0",
  "com.lihaoyi" %% "ammonite-ops" % "2.0.4",
  "commons-io" % "commons-io" % "2.6",
  "com.typesafe.slick" %% "slick-hikaricp" % slickVersion,
  "com.h2database" % "h2" % "1.4.200",
  "org.xerial" % "sqlite-jdbc" % "3.8.11.2",// 3.30.1 crashes SQLiteCommandTests
  "mysql" % "mysql-connector-java" % "5.1.38",
  "org.postgresql" % "postgresql" % "42.2.9",
  "org.hsqldb" % "hsqldb" % "2.5.0",
  "org.apache.derby" % "derby" % "10.14.2.0",
  "ch.qos.logback" % "logback-classic" % "1.2.3"
).map(_ % "test")

lazy val commonSettings = Seq(
  organization := "com.liyaos",
  licenses := Seq("Apache 2.0" ->
    url("https://github.com/lastland/scala-forklift/blob/master/LICENSE")),
  homepage := Some(url("https://github.com/lastland/scala-forklift")),
  scalaVersion := scala213,
  scalacOptions += "-deprecation",
  scalacOptions += "-feature",
  resolvers += Resolver.jcenterRepo,
  publishMavenStyle := true,
  publishArtifact in Test := false,
  repoKind := { if (version.value.trim.endsWith("SNAPSHOT")) "snapshots"
                else "releases" },
  publishTo := { repoKind.value match {
    case "snapshots" => Some("snapshots" at
        "https://oss.sonatype.org/content/repositories/snapshots")
    case "releases" =>  Some("releases"  at
        "https://oss.sonatype.org/service/local/staging/deploy/maven2")
  }},
  credentials += Credentials(Path.userHome / ".ivy2" / ".credentials"),
  pomExtra := (
    <scm>
      <url>git@github.com:lastland/scala-forklift.git</url>
      <connection>scm:git:git@github.com:lastland/scala-forklift.git</connection>
      </scm>
      <developers>
      <developer>
      <id>lastland</id>
      <name>Yao Li</name>
      </developer>
      </developers>))

// Derby is running is secured mode since version 10.12.1.1, so security manager must be disabled for tests  
// https://stackoverflow.com/questions/48008343/sbt-test-does-not-work-for-spark-test
// https://issues.apache.org/jira/browse/DERBY-6648
Test / testOptions += Tests.Setup(() => System.setSecurityManager(null))

lazy val root = Project(
  "scala-forklift", file(".")).settings(
  crossScalaVersions := Nil,
  publishArtifact := false).aggregate(
  coreProject, slickMigrationProject, plainMigrationProject, gitToolProject, example)

lazy val coreProject = Project(
  "scala-forklift-core", file("core")).settings(
  commonSettings:_*).settings {Seq(
    crossScalaVersions := supportedScalaVersions,
    coreDependencies
  )}

lazy val slickMigrationProject = Project(
  "scala-forklift-slick", file("migrations/slick")).dependsOn(
  coreProject).settings(commonSettings:_*).settings { Seq(
    crossScalaVersions := supportedScalaVersions,
    libraryDependencies ++= slickDependenciesWithTests
  )} 

lazy val plainMigrationProject = Project(
  "scala-forklift-plain", file("migrations/plain")).dependsOn(
  coreProject).settings(commonSettings:_*).settings(crossScalaVersions := supportedScalaVersions)

lazy val gitToolProject = Project(
  "scala-forklift-git-tools", file("tools/git")).dependsOn(
  coreProject).settings(commonSettings:_*).settings(crossScalaVersions := supportedScalaVersions)

///////////////////////////////////////////////

name := "forklift-slick-example"

addCommandAlias("mgm", "example/migration_manager/run")

addCommandAlias("mg", "example/migrations/run")

lazy val exampleCommonSettings = Seq(
  organization := "com.liyaos",
  version := "2.0",
  scalaVersion := "2.13.1",
  scalacOptions += "-deprecation",
  scalacOptions += "-feature",
  resolvers += Resolver.sonatypeRepo("snapshots"),
  resolvers += Resolver.jcenterRepo,

)

lazy val loggingDependencies = List(
  "org.slf4j" % "slf4j-nop" % "1.6.4" // <- disables logging
)

lazy val exampleSlickDependencies = List(
  "com.typesafe.slick" %% "slick" % slickVersion
)

lazy val dbDependencies = List(
  "com.typesafe.slick" %% "slick-hikaricp" % slickVersion
  ,"com.h2database" % "h2" % "1.4.200"
)

lazy val forkliftDependencies = List(
//  "com.liyaos" %% "scala-forklift-slick" % forkliftVersion
)

lazy val appDependencies = dbDependencies ++ loggingDependencies

lazy val migrationsDependencies =
  dbDependencies ++ forkliftDependencies ++ loggingDependencies

lazy val migrationManagerDependencies = dbDependencies ++ forkliftDependencies

lazy val example = Project("example", file("example")).aggregate(
  app, migrations, migrationManager, generatedCode, tools).settings(
  exampleCommonSettings:_*)

lazy val app = Project("app", file("example/app"))
  .dependsOn(generatedCode)
  .settings(exampleCommonSettings:_*)
  .settings {libraryDependencies ++= appDependencies}

lazy val migrationManager = Project("migration_manager", file("example/migration_manager"))
  .dependsOn(slickMigrationProject)
  .settings(exampleCommonSettings:_*)
  .settings {libraryDependencies ++= migrationManagerDependencies}

lazy val migrations = Project("migrations", file("example/migrations"))
  .dependsOn(generatedCode, migrationManager, slickMigrationProject)
  .settings(exampleCommonSettings:_*)
  .settings {libraryDependencies ++= migrationsDependencies}

lazy val tools = Project("git-tools", file("example/tools/git"))
  .dependsOn(slickMigrationProject, gitToolProject)
  .settings(commonSettings:_*)
  .settings {
    libraryDependencies ++= forkliftDependencies ++ List(
//    "com.liyaos" %% "scala-forklift-git-tools" % forkliftVersion,
      "com.typesafe" % "config" % "1.3.0",
      "org.eclipse.jgit" % "org.eclipse.jgit" % "4.0.1.201506240215-r"
    )
  }

lazy val generatedCode = Project("generate_code", file("example/generated_code"))
  .settings(exampleCommonSettings:_*)
  .settings {libraryDependencies ++= exampleSlickDependencies}

Question:

Is there a simple way I can replace the scala-forklift-slick Maven package reference in /example/build.sbt with a link to the existing scala-forklift-slick project definition in the parent directory's build.sbt so I can use .dependsOn(...) instead?

Or maybe it's better to do something like build scala-forklift-slick and use a local disk package resolver?

Daniel
  • 8,655
  • 5
  • 60
  • 87
  • 1
    It would be way easier to just do a local publish of the forked library and reference that as another library. – Luis Miguel Mejía Suárez Feb 27 '22 at 15:28
  • @LuisMiguelMejíaSuárez you're right! It was much easier to do it this way. I'll post this as the answer but if you post an answer with the same steps I'll delete mine and mark yours as the accepted one. – Daniel Feb 27 '22 at 16:15

1 Answers1

1

Luis Miguel Mejía Suárez's comment worked perfectly and was the easier approach.

In the context of this project, all I had to do was:

  1. Append -SNAPSHOT to the version in /version.sbt (should not be needed normally but for this project I had to do this)
  2. Run sbt publishLocal in the parent project.

After this, the example project (which already targets the -SNAPSHOT version) is able to pick up the locally built package.

Daniel
  • 8,655
  • 5
  • 60
  • 87
  • I am pretty sure `publishLocal` would automatically add that `SNAPSHOT` unless they do something weird with versioning – Luis Miguel Mejía Suárez Feb 27 '22 at 16:38
  • Oh ok, let me try that out and update the answer accordingly. – Daniel Feb 27 '22 at 18:11
  • 1
    @LuisMiguelMejíaSuárez I think you're right and this project does something weird with the versioning because I did a full clean but doing the `publishLocal` straight from the `develop` branch creates a `0.3.2` version in my local ivy2 repository instead of `0.3.2-SNAPSHOT` and the example project isn't able to find the package. – Daniel Feb 27 '22 at 18:24