"Filename too long" in sbt assembly inside a docker container - scala

I have a scala Play project and I need to create a fat jar in the docker build time but I get this error:
[warn] Error extracting zip entry [...] (File name too long)
I tried adding the option scalacOptions ++= Seq("-Xmax-classfile-name","72") in build.sbt but doesn't works. I tried also appending -Xmax-classfile-name=72 to sbt assembly with the same result.
As I need to do it in docker build time, I can't use a mounted volume as mentioned here https://github.com/sbt/sbt-assembly/issues/69#issuecomment-196901781
What do I need to do to fix this?

In /project/plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")
and in build.sbt
assemblyJarName in assembly := "jarname.jar"
target in assembly := baseDirectory.value
Then run command "assembly" from project root and should generate the jar file.

Related

How to exclude classes from compiling when using executing sbt docker:publishLocal?

My build.sbt file has some configuration to use AkkaGrpcPlugin and DockerPlugin because I am publishing the image at docker hub.
lazy val akkaGrpcVersion = "1.0.2"
lazy val protobufVersion = "3.11.4"
enablePlugins(JavaAppPackaging, JavaServerAppPackaging, AkkaGrpcPlugin, DockerPlugin)
akkaGrpcGeneratedLanguages := Seq(AkkaGrpc.Java)
libraryDependencies ++= Seq(
......
)
dockerUsername := Some("felipeogutierrez")
The sbt compile and sbt run work just fine, but the command sbt docker:publishLocal is not working because it tries to find some classes created by the gRPC in the target directory.
[error] /home/felipe/workspace-idea/explore-akka/target/scala-2.12/
akka-grpc/main/org/github/felipegutierrez/explore/akka/rpc/greeting/HelloRequest.java:29:7:
not found: type UnusedPrivateParameter
[error] UnusedPrivateParameter unused) {
[error] ^
these classes belong to the classes at package org.github.felipegutierrez.explore.akka.rpc.greeting and I would like to exclude them from the docker image when I am running sbt docker:publishLocal. I tried this solution but it didn't work. Or find some solution to make this work.
The problem was that I generated the Java files using AkkaGrpcPlugin and they were placed on the target directory of my project. So the docker compiler could not see it. I removed the AkkaGrpcPlugin and the akkaGrpcGeneratedLanguages := Seq(AkkaGrpc.Java) from the build.sbt and installed the protobuf compiler to generate the Java files by myself.
sudo apt install protobuf-compiler
protoc --java_out=main/java main/protobuf/helloworld.proto
Then the files are now generated on the src directory and Docker can see them. So, I don't have to exclude the files anymore in the build.sbt.

Why do I have to add jars to class path to run the jar file when I already have the dependency added in my project?

I am working on a Scala project on IntelliJ with SBT as my build tool. I started working sbt build recently.
This is my project structure:
This is my build.sbt file:
name := "AnalyzeTables"
version := "0.1"
scalaVersion := "2.11.8"
// https://mvnrepository.com/artifact/org.postgresql/postgresql
libraryDependencies += "org.postgresql" % "postgresql" % "42.1.4"
// https://mvnrepository.com/artifact/commons-codec/commons-codec
libraryDependencies += "commons-codec" % "commons-codec" % "1.13"
// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.8.1"
// https://mvnrepository.com/artifact/log4j/log4j
//libraryDependencies += "log4j" % "log4j" % "1.2.17"
I have Class.forName("org.postgresql.Driver) in my code to connect to database and query. Along with that, I have password decryption & logger added in the code.
I am running the jar in the below format:
scala <jarname> <argument I use in my code>
The problem here is if I just submit in the way I mentioned above, I see ClassNotFoundException for postgres driver. So I add it to the classpath of the jar and submit it as below.
scala -cp /path/postgresql-42.1.4.jar <jarname> <argument I use in my code>
Now I get exception for Logger. So I add it to classpath again and it becomes:
scala -cp /path/postgresql-42.1.4.jar:/path/log4j-1.2.17.jar <jarname> <argument I use in my code>
Now I get exception for commons-codec, so I added that as well.
scala -cp /path/postgresql-42.1.4.jar:/path/log4j-1.2.17.jar:/path/commons-codec-1.13.jar
Now that jar is running fine and I can see the result.
So I have the dependencies added to the build.sbt file. I also did the below operation:
project structure -> Modules -> Dependencies -> + -> jars -> Add all the missing jars that are giving problems
If I remove all the -cp parameters and submit the jar with just: scala <jarname> <argument> it goes back again to ClassNotFoundException to postgres jar.
So what is the point of adding dependencies on build.sbt file and then add them in the classpath again ?
Is there ay setting I am missing or am I looking it in the wrong way ?
Edit:
After suggestions I created a new project & copied all the code into it and added the plugin addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5") in a new file plugins.sbt file which I created in the dir /project/ as shown in the image below.
I can see the plugin in the sbt-plugins dir. But when I build the jar once again and export, it still shows 11kb jar instead of a fat jar.

How to activate the sbt DockerPlugin in scala?

I have two scala projects, one is already defined to build its docker container through the sbt docker plugin. The other one I want to dockerify as well.
The working one has in its build.sbt the following lines relevant to the docker config:
organization := "com.namespace"
name := "dockerized-app"
version := sys.env.getOrElse("PIPELINE_VERSION", "0.1.0_local")
scalaVersion := "2.12.4"
enablePlugins(JavaAppPackaging)
enablePlugins(DockerPlugin)
packageName in Docker := packageName.value
dockerRepository := Some("our-docker.io:5001")
dockerExposedPorts := Seq(8080)
I thought that I could copy paste the relevant lines to the new project, change the name, and make it work.
Yet when I add the line to the about to be dockerified scala project:
enablePlugins(DockerPlugin)
I get the error:
Cannot resolve symbol DockerPlugin
I've looked through the prexisting projects libraryDependencies, yet it doesn't seem to be configured that way. In the the pre-configured project, IntellJ somehow knows the plugin, I can track that the DockerPlugin comes from com.typesafe.sbt.packager.docker. This made me assume that sbt comes shipped with it by default.
Yet apparently I have to activate it somehow.
Digging deeper I also tried adding this to my plugins.sbt to no avail:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.2")
How to activate DockerPlugin using sbt in scala?
In order to make it working properly you need to add the following line:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.2")
in your project/plugins.sbt file.
Then refresh your project and it should work.
For further information, please check the Sbt Native Packager documentation.

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.

sbt-native-packager and RPM - how do I set required parameters?

I'm finding it diffuclt to build a Play project using the sbt native packager. I don't know where to set the RPM configuration when I am given the following error:
[error] `rpmVendor in Rpm` is empty. Please provide a valid vendor for the rpm SPEC.
[error] `packageSummary in Rpm` is empty. Please provide a valid summary for the rpm SPEC.
[error] `packageDescription in Rpm` is empty. Please provide a valid description for the rpm SPEC.
I've set the following in project/plugins.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.8.0")
In my build.sbt:
name := """supersecretproject"""
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.1"
libraryDependencies ++= Seq(
jdbc,
anorm,
cache,
ws
)
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.27"
javacOptions ++= Seq("-source", "1.6", "-target", "1.6")
tomcat()
The documentation merely states:
A rpm package needs some mandatory settings to be valid. Make sure you have these settings in your build:
rpmRelease := "1"
rpmVendor := "typesafe"
rpmUrl := Some("http://github.com/paulp/sbt-extras")
rpmLicense := Some("BSD")
Which is almost entirely useless if you don't know SBT very well! How do I "have these settings in your build:" as the documentation instructs?
I've tried adding the above "settings" to build.sbt or a separate packageSettings.sbt but with no luck as I just get the following error:
error: not found: value rpmRelease
rpmRelease := "1"
^
[error] Type error in expression
Note: I run the sbt using sbt rpm:packageBin
It sounds like the developers of that plugin are trying to not be too prescriptive, but in doing so have not given you enough information to even get started! :-(
The simplest possible solution: Copy those four settings (including the blank lines between) into your build.sbt.
A logical place is probably towards the bottom of the file, as "packaging" your app is something that happens "towards the end" of the development cycle.
Another option: SBT automatically combines the contents of all .sbt files it finds in the project root. So if you prefer, you could create a new file such as packagingSettings.sbt and put those settings in there.
Edit: Help with imports:
Whichever option you choose, you'll need to add the following imports at the top of the file (as per the getting started guide):
import com.typesafe.sbt.SbtNativePackager._
import NativePackagerKeys._