Add Multiple scalapb Source Directories to Multi-Project SBT Build - scala

I'm having some difficulties understanding the syntax for scalapb, specifically I'm trying to add multiple .proto source directories for a multi-project SBT build.
My project structure is as follows:
/build.sbt
/main/src/protobuf
/common/main/src/protobuf
/client/main/src/protobuf
My build.sbt is as follows:
name := "myApp"
import Dependencies._
import com.trueaccord.scalapb.{ScalaPbPlugin => PB}
val protoDirectories = Seq(
file("common/src/main/protobuf"),
file("client/src/main/protobuf")
)
sourceDirectories in PB.protobufConfig ++= protoDirectories
PB.protobufSettings ++ Seq(
flatPackage := false
)
lazy val common = (project in file("common")).
settings(Commons.settings: _*).
settings(libraryDependencies ++= commonDependencies)
lazy val client = (project in file("client")).
settings(Commons.settings: _*).
settings(libraryDependencies ++= clientDependencies).
dependsOn(common)
When I run sbt compile, I get the following error message:
[error] Reference to undefined setting:
[error]
[error] sphere/*:sourceDirectories from myApp/*:sourceDirectories (<path_to_project_dir>\build.sbt:11)
[error] Did you mean myApp/protobuf:sourceDirectories ?
Could someone please point me in the right direction? I'm failing to understand some basic concept here...
EDIT
Ok, so I was pointing to the wrong sequence for the protoDirectories. I have amended the build.sbt to reflect the new changes. I still have a problem that my .proto files are not compiled in the sub projects. If I move my .proto files to the root /main/src/protobuf, they compile just fine.

You need to enable the ScalaPB plugin for both projects separately if both contain files in src/main/protobuf. This example also shows how to set the import search path. A full example is at https://github.com/thesamet/scalapb-test/tree/multiproject
import com.trueaccord.scalapb.{ScalaPbPlugin => PB}
version in PB.protobufConfig := "3.0.0-beta-2"
lazy val common = (project in file("common")).
settings(PB.protobufSettings)
lazy val client = (project in file("client")).
settings(PB.protobufSettings ++ Seq(
// If you want proto files in client to import proto files in common.
PB.includePaths in PB.protobufConfig += file("common/src/main/protobuf")
)).
dependsOn(common)

Related

scala using github repo as a libraryDependencies

I was facing one error while trying using RootProject
I need to use gatling snapshot version which is 3.5.0-SNAPSHOT and to enable this I know two options:-
using git clone and then sbt publishLocal finally using this jar as an unmanaged dependency, This works fine but it is rather more manual work, So I moved to the second option.
Using sbt RootProject, so let me first explain the project setup:-
example/Build.sbt
lazy val gatling = RootProject(uri("https://github.com/gatling/gatling.git"))
lazy val root = (project in file("."))
.settings(
name := "example",
version := "0.1",
scalaVersion := "2.13.3"
).dependsOn(gatling)
example/project/plugins.sbt -> These two were added because it was required while building the project
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.21")
libraryDependencies += "org.scala-sbt" %% "io" % "1.4.0"
example/src/main/scala/Main.scala
import io.gatling.core.scenario.Simulation
object Main extends App {
class A extends Simulation
val a = new A
println(a.toString)
}
So after this executing sbt run will result in a successful build.
But the problem starts when I tried to import gatling-highcharts in a similar fashion as:-
lazy val gatling = RootProject(uri("https://github.com/gatling/gatling.git"))
lazy val gatlingHighCharts = RootProject(uri("https://github.com/gatling/gatling-highcharts.git"))
lazy val root: Project = (project in file("."))
.settings(
name := "example",
version := "0.1",
scalaVersion := "2.13.3"
).dependsOn(gatling, gatlingHighCharts)
now executing sbt will result in an error as:-
[error] not found: C:\Users\user\.ivy2\local\io.gatling\gatling-recorder\3.5.0-SNAPSHOT\ivys\ivy.xml
[error] not found: https://repo1.maven.org/maven2/io/gatling/gatling-recorder/3.5.0-SNAPSHOT/gatling-recorder-3.5.0-SNAPSHOT.pom
[error] not found: https://jcenter.bintray.com/io/gatling/gatling-recorder/3.5.0-SNAPSHOT/gatling-recorder-3.5.0-SNAPSHOT.pom
And this was because gatling is being used via dependsOn while actually there is nothing available to do like:-
lazy val gatlingHighCharts = RootProject(uri("https://github.com/gatling/gatling-highcharts.git")).dependsOn(gatling)
This is not possible as there is no method named dependsOn inside RootProject class and I am not able to figure out how to make that work.
Can anyone help me to figure out how can I make that work?
Plus, if somehow exist a way to use github repo jars directly as managed sources instead of unmanaged sources which is something like
libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % "3.5.0-SNAPSHOT"
without using dependsOn.

"object is not a member of package" when importing dependency built from another project via slick codegen

I have a multi project setup like this:
lazy val kalosrpc = project
.settings(
libraryDependencies ++= Seq(
"io.grpc" % "grpc-netty" % scalapb.compiler.Version.grpcJavaVersion
)
).dependsOn(kalosgen)
lazy val kalosgen = project
.settings(
// settings not important
)
The main class of kalosgen generates a model via slick-codegen and places is it in:
kalosgen/target/scala-2.13/src_managed/main
in the package com.kalos.gen. It also compiles protobufs into scala classes at compile time but that package is in the classpath as expected.
I can then import those files from kalosgen into kalosrpc, intelliJ does not complain and has full access to the type information defined in those files. So I run kalosgen/compile and the packages are generated as I expect however when I follow that up with kalosrpc/compile I get:
object gen is not a member of package com.kalos
I've tried changing the name of the packages but it doesn't fix anything. Based on the information presented here my project configuration seems correct.
Try executing show sourceManaged from sbt which should output the location of where generated files should end up, for example in my project it is at
.../myproject/target/scala-2.13/src_managed
It likely should be
kalosgen/target/scala-2.13/src_managed/main/com/kalos/gen
instead of
kalosgen/target/scala-2.13/main/com/kalos/gen
Also double check generated files have package statements at the top.
The problem here was that I was generating the sources in scala code via the slick-codegen utility:
import slick.codegen.SourceCodeGenerator
object Main extends App {
val url = "hidden"
val user = "hidden"
val password = "hidden"
val dbDriver = "com.mysql.jdbc.Driver"
val profile = "slick.jdbc.MySQLProfile"
SourceCodeGenerator.main(
Array(
profile,
dbDriver,
url,
"./kalosgen/target/scala-2.13/src_managed/main",
"com.kalos.gen",
user,
password
)
)
}
My guess is that you have to generate sources via SBT tasks to have them recognized by SBT as being valid sources (at least for the purposes of inter project dependencies), so I was able to translate the above code to a task that runs at compile time in build.sbt:
lazy val gen = project
.settings(
libraryDependencies ++= Seq(
"dependencies"
),
sourceGenerators in Compile += Def.task {
val outDir = (sourceManaged in Compile).value.getPath
(runner in Compile).value.run(
"slick.codegen.SourceCodeGenerator",
(dependencyClasspath in Compile).value.files,
Array(
"slick.jdbc.MySQLProfile",
"com.mysql.jdbc.Driver",
"url",
outDir,
"com.kalos.gen",
"username",
"password"
),
streams.value.log
)
Seq(file(outDir + "/com/kalos/gen/Tables.scala"))
}.taskValue
)
Now the generated Tables.scala appears as expected in the class path and my project compiles. If someone with more knowledge of sbt could provide a more comprehensive explanation of why this happened I will gladly accept it as the proper answer.

trait Build in package sbt is deprecated: Use .sbt format instead

Using sbt 0.13.5, when opening the project in IntelliJ, there is a warning message
~\myproject\project\Build.scala:5: trait Build in package sbt is
deprecated: Use .sbt format instead
The content of the Build.scala is
import sbt._
object MyBuild extends Build {
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(Testing.settings ++ Docs.settings: _*)
}
The Appendix: .scala build definition and the sbt documentation is rather overwhelming.
How to merge my existing Build.scala to build.sbt? Would appreciate any direction to doc/tutorial/examples.
Rename Build.scala to build.sbt and move it up one directory level, so it's at the top rather than inside the project directory.
Then strip out the beginning and end, leaving:
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(Testing.settings ++ Docs.settings: _*)
That's the basics.
Then if you want to add more settings, for example:
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(
Testing.settings,
Docs.settings,
name := "MyApp",
scalaVersion := "2.11.8"
)
You don't need the :_* thing on sequences of settings anymore in sbt 0.13.13; older versions required it.
The migration guide in the official doc is here: http://www.scala-sbt.org/0.13/docs/Migrating-from-sbt-012x.html#Migrating+from+the+Build+trait

How to set up multi-module build with reference to external local sbt project?

I just started with Scala and Play and I'm trying to set up a multi build with sbt 0.13.5
My project structure is the following:
/AnormCypher
-> /src
->/main
->/scala
->org.anormcypher[package]
->[Some classes]
-> [other dirs/files]
-> build.sbt
/sample
-> /src
->/main
->/scala
->/controllers[package]
->Application.scala
->[Some classes]
-> [other dirs/files]
-> build.sbt
The sample project depends on the AnormCypher project. I tried to set up the dependency following this SO post. My build.sbt in sample looks like this:
name := """sample"""
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.1"
libraryDependencies ++= Seq(
jdbc,
anorm,
cache,
ws
)
lazy val core = ProjectRef(file("../AnormCypher"), "anormcypher")
val main = root.dependsOn(core)
When I go into my console and type
activator
sbt is able to load the project. But when I try to compile the sources and try to use classes from the org.anormcypher package, they can't be resolved:
object anormcypher is not a member of package org
[error] import org.anormcypher._
[error] ^
Running a clean compile also brought no results.
Change
lazy val root = (project in file(".")).enablePlugins(PlayScala)
to
lazy val root = (project in file(".")).enablePlugins(PlayScala).dependsOn(core)
and remove
val main = root.dependsOn(core)
reload and the project should work fine.

SBT: Access managed resources of a subproject?

In an SBT Plugin, I'm trying to access to managed resources of subprojects.
Here is the build file:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "demo"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"org.jruby" % "jruby-complete" % "1.7.1"
)
val widgets = play.Project("widgets", appVersion, appDependencies, path = file("widgets"))
val main = play.Project(appName, appVersion, appDependencies, path = file("demo"))
.dependsOn(widgets)
}
I'm working in an SBT plugin defined in plugins.sbt.
Now, I need to use resources files from the subproject (widgets) during compilation of the parent project (demo).
So far the closest I've got to is the buildDependencies settings key - but I'm only getting ProjectRef objects, and the only information is the build base and the project id. I couldn't find a way to get to that project's resources directory.
I'm not familiar with writing plugins, but at least in your build.sbt you can define the resource file.
Or, again in the build.sbt you can create a "common" project that others reference, like:
lazy val common = (project in file("common"))
.settings(
Seq(
includeFilter in unmanagedResources := new SimpleFileFilter(_.getCanonicalPath.startsWith((sourceDirectory.value / "main" / "resources").getCanonicalPath))
)
)
Then other code (e.g. a Task) could reference this like:
lazy val doSomething = taskKey[Seq[File]]("Does something useful")
lazy val doSomethingSetting = doIt := {
val resourceDir = (resourceDirectory in common in Compile).value
println(resourceDir)
}
So your other projects could run this or reference that directory
Hopefully there's a straight forward way to implement one of those solutions for a plugin vs a build?
Unfortunately I do not believe this is possible. I was trying something similar but found the following in the documentation:
Note: At runtime, all plugins for all builds are loaded in a separate, parent class loader of the class loaders for builds. This means that plugins will not see classes or resources from build definitions
See: SBT Plugins