SBT-java.lang.RuntimeException: No main class detected - scala

sbt compile gives Success
sbt run gives the error mentioned above.
My Directory Structure is a little bit different from the regular SBT structure:
Directory structure that I need... Build.sbt inside main project
Build.sbt inside SubProject
MainClass.scala
object MainClass extends App {
println("Hello world!")
}
Note: Things I have already tried in Build.sbt of main project:
1. scalaSource in (Compile, run) := baseDirectory.value / "App" / "js"
2. mainClass in (Compile, run) := Some("MainClass")
3. mainClass in (Compile, run) := Some("App/js/src/main/scala/MainClass")
I am not able to figure out the mistake?

It is not possible to declare additional projects in .sbt files that are in subdirectories. All projects have to be declared in .sbt files at the root of build.
This means that your AppJs and AppJvm never get to have any effect, and those projects do not actually exist in your build.
You'll have to declare AppJs, AppJvm, and any other project you need in the top-level build.sbt file.

Related

Set mainClass for sbt native packager Universal

I have a project that has the following build.sbt:
addCommandAlias("package", "dist")
lazy val actual = (project in file("."))
.enablePlugins(UniversalPlugin, JavaServerAppPackaging)
.settings(
name := "DeployerPod",
mainClass := Some("com.myself.executable.Runner"),
Compile / mainClass := Some("com.myself.executable.Runner"),
Compile / run / mainClass := Some("com.myself.utils.Pipeline"),
Universal / mainClass := Some("com.myself.executable.Runner"),
Universal / compile / mainClass := Some("com.myself.executable.Runner"),
)
We have a CICD which runs a Dockerfile.
There I have sbt run as one of the steps, which will execute com.myself.utils.Pipeline class to run a Scala class and do the pre requisites for the pipeline.
As one of the last sbt based steps, I'm also running sbt package, which eventually runs an sbt dist command. At this point, inside the extracted ZIP's bin folder, I see two BAT files corresponding to the two main classes. Unfortunately I only want the Runner class BAT instead of Pipeline BAT.
For this I tried running sbt package -main com.myself.executable.Runner but that failed saying Not a valid command: -
Is there a way I can specify the mainClass only for this Universal plugin somehow? Because the way I've tried in my build.sbt doesn't seem to work.

project directory for sbt sub-projects

can a sbt sub project have its own project directory? or only the root project can project directory with .scala helper files for the build?. Below is my current build scructure. The /my-project/sub-projects/sub-project-1/build.sbt is not able to access objects defined in /my-project/sub-projects/sub-project-1/SubProjectHelper.scala.
/my-project
build.sbt
/projects
Helper.scala
sub-projects
sub-project-1
build.sbt
/projects
SubProjectHelper.scala
Update:
The below sbt definition in sub-project-1/build.sbt
lazy val localhost = (project in file(".")).settings (
name := """localhost""",
version := Common.version,
scalaVersion := Common.scalaVersion,
libraryDependencies ++= Common.dependencies,
libraryDependencies ++= Localhost.dependencies
)
is failing with the below error
libraryDependencies ++= Localhost.dependencies
^
sbt.compiler.EvalException: Type error in expression
at sbt.compiler.Eval.checkError(Eval.scala:384)
at sbt.compiler.Eval.compileAndLoad(Eval.scala:183)
at sbt.compiler.Eval.evalCommon(Eval.scala:152)
at sbt.compiler.Eval.evalDefinitions(Eval.scala:122)
at sbt.EvaluateConfigurations$.evaluateDefinitions(EvaluateConfigurations.scala:271)
at sbt.EvaluateConfigurations$.evaluateSbtFile(EvaluateConfigurations.scala:109)
at sbt.Load$.sbt$Load$$loadSettingsFile$1(Load.scala:712)
Common is defined in /my-project/projects/Common.scala and has no issues. But Localhost is defined in /my-project/sub-projects/sub-project-1/projects/SubProjectHelper.scala is not properly resolved in the sub-project-1 build.sbt
Yes, they can, and you even don't need to have sub-projects dir, just place sub-project-1 in my-project dir.
Usually (at least this is what scala/scala-seed.g8 ends up with) project subdirectory doesn't ends with an extra s like your directory structure.
You should rename projects to project.
The answer is no, unfortunately. As seen here
You cannot have a project subdirectory or project/*.scala files in the sub-projects. foo/project/Build.scala would be ignored.

Problems finding Main class in sub-directories w/SBT assembly

I am attempting to use SBT assembly(0.14.0) to create a fat jar of my Scala project.
My project structure is as follows:
>top
> build.sbt
> api
> src
> main
> scala
> name
> Boot.scala
> other directories
I am trying to set Boot as the main method to be run in the jar.
I have tried using:
baseDirectory in (Compile,run) := file("api")
scalaSource in run := baseDirectory.value / "api"
scalaSource in Compile := baseDirectory(_ / "api")
mainClass in assembly := some("name.Boot")
The jar builds successfully but when running it I receive the error:
Error: Could not find or load main class name.Boot
Going by the snippet you posted, you could try changing
mainClass in assembly := some("name.Boot")
to
mainClass in assembly := Some("name.Boot")
The reason it does not complain is that lower case some refers to something else.
The file path of your mainClass isn't relevant, only the namespace in Scala/Java. Is your main object
package name
object Boot {
def main ...
}
?

publish jar files with sbt (3rd party)

Hello I have 5 jar files and tried to publish them to a local repository with sbt.
But when I place them in unmanagedBase directory like lib/ they won't get copied with publishLocal. Is there an easy way to include them in the publishing process?
Currently maven has a similar solution here:
http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html
One option is to define a subproject for each jar that you want published. Have your main project depend on each. Give each subproject an appropriate name, version, and organization. For each subproject, put its jar somewhere not on the classpath and make the output of packageBin be that jar.
For example (sbt 0.13 build.sbt),
lazy val main = project.dependsOn(subA)
lazy val subA = project.settings(
name := "third-party",
organization := "org.example",
version := "1.4",
packageBin in Compile := baseDirectory.value / "bin" / "third-party.jar",
// if there aren't doc/src jars use the following to
// avoid publishing empty jars locally
// otherwise, define packageDoc/packageSrc like packageBin
publishArtifact in packageDoc := false,
publishArtifact in packageSrc := false,
// tell sbt to put the jar on main's classpath
// and not the (empty) class directory
exportJars := true,
// set this to not add _<scalaBinaryVersion> to the name
crossPaths := true
)
This approach allows you to change the jar in subA/bin/third-party.jar and have it be used immediately and a subsequent publishLocal will publish it locally.
If you prefer separately publishing it locally, so that it isn't part of the project, define subA as a standalone project instead.

How to configure sbt to load resources when running application?

My code (Java) reads an image from jar:
Main.class.getResourceAsStream("/res/logo.png")
Everything runs fine (if I start the app after packaging it into a jar). But when I run it using sbt's run task, it returns me null instead of needed stream.
Running this from sbt console also gives null:
getClass.getResourceAsStream("/res/logo.png")
Is there a way to tell sbt to put my resources on classpath?
EDIT:
I set the resources dir to be same as source dir:
build.sbt:
resourceDirectory <<= baseDirectory { _ / "src" }
When I loaded sbt's `console' and ran the following:
classOf[Main].getProtectionDomain().getCodeSource()
I got the location of my classes, but it does not contain neither res folder nor any of my resource files.
Seems that sbt copies resources only to the resulting jar, and does not copy them to classes dir. Should I modify compile task to move these resources files to classes dir?
EDIT2:
Yes, when I manually copy the resource file to classes dir, I can easily access it from console. So, how should I automate this process?
EDIT3:
It seems that sbt is just unable to see my resource folder - it does not add files to resulting jar file, actually!
Solution:
resourceDirectory in Compile <<= baseDirectory { _ / "src" }
I can't give you a full solution right now, but there is a setting called resourceDirectories to which you could add the res folder.
[EDIT]
For me it didn't work also if the resource was in the standard resource folder. Please try it that way:
Main.class.getClassLoader().getResourceAsStream("icon.png")
[EDIT2] This is the full build script (build.scala) which works if your resource is in src/main/java:
import sbt._
import Keys._
object TestBuild extends Build {
lazy val buildSettings = Seq(
organization := "com.test",
version := "1.0-SNAPSHOT",
scalaVersion := "2.9.1"
)
lazy val test = Project(
id = "test",
base = file("test"),
settings = Defaults.defaultSettings ++ Seq(resourceDirectory in Compile <<= javaSource in Compile)
)
}