Preserve results of sbt incremental compilation when moving project directory - scala

Consider the scenario: I have a simple scala project managed by sbt, in a directory called foo.
cd foo
sbt compile
It now takes a few seconds and the project compiles correctly.
Now, thanks to sbt incremental compilation, if I run
sbt compile
it terminates the compile task in close to 0 seconds, since the source code hasn't changed.
But if I rename the foo directory into bar
cd ..
mv foo bar
and try to compile it again
cd bar
sbt compile
now the compile task takes again few seconds, hence not using the results from the previous compilation.
Is there a way to preserve the incremental compilation results of a project even when its absolute path on disk has changed?

You can also try to use Hoarder Plugin: https://github.com/romanowski/hoarder.
Ping me on Hoarder's gitter in case of any questions/problems.

As it turns out, there's some work in progress to make incremental compilation results cacheable. Here's the relevant PR: https://github.com/sbt/zinc/pull/216.
Also, there's an issue (being discussed at the time of this writing) about making zinc's analysis completely machine independent. See https://github.com/sbt/zinc/issues/218.

Related

Problems compiling and running Scala projects in IntelliJ Idea

I have installed the latest IntelliJ Idea vertion with the Scala plugin. I have created a SBT Scala project with the IDE.
Unfortunately, I am not able to compile or run even the simplest "Hello World" example.
object Main {
def main(args: Array[String]): Unit ={
val x: Int = 5
println("Hello Scala!")
println(x)
}
}
If I try to run it, it says that "Error: could not find main class Main".
Rebuilding the project does not help.
BUT, if I run the "sbt" terminal program and execute "run", everything runs fine. Even more, it compiles the necessary class file so that IntelliJ Idea is able to run it after this step.
But, whenever I change something in the code and try to rebuild it from Idea, it will fail as before.
Edit: in Eclipse everything runs ok.
UPDATE
If I try executing "compile" from the sbt shell and then "Run" with the IDE, it will work. But, it will not do it while executing "Build" or "Rebuild Project". Sometimes, but unfortunately not always sp as to be able to reproduce it, it will throw me an exception with "Could not initialize class sbt.internal.io.Milli$"
UPDATE 2nd:
I have simplified even more the task. Now I have something like the following screenshot:
Screenshot IntelliJ IDEA
UPDATE 3rd:
There were two errors in my deployment. One of them was that, as it was pointed before, there was some package definition problems. All the source code should depend on src/main/scala, but that is not enough. So as to use the SBT structure for construction, I had to go to
File -> Settings -> Build, Execution, Deployment -> Build Tools -> sbt
and check "Use auto-import" and "use sbt shell for build and import".
After that, everything runs ok. Finall!
Thanks a lot tro everyone for the useful input!
On your screenshot Runner is in wrong package. It's written package main.scala.
If Runner.scala is in src/main/scala/way/to/my/package package declaration should be package way.to.my.package (if it's just in src/main/scala there should not be line package ...).
Also if still necessary you can try (from what should be tried first to what should be tried last, if things tried before didn't help)
sbt clean
reimport the project to IntelliJ IDEA
File -> Invalidate Caches / Restart ...
delete .idea subfolder of project folder
Did you try the green arrow near "object Main"?
This should start the program.

How to synchronize Intellij and sbt builds for a scala project

I have an sbt project that I have imported into Intellij. Sometimes I build the project at the command line using sbt, and then when I need to debug I build it from within Intellij. However, each time I alternate it requires a full rebuild when there is no need. Both build procedures output to the same class folder, namely .../target/scala-2.11/classes, so I don't understand why a full rebuild keeps happening?
As stated by CrazyCoder, intellij and sbt build have each their own tracking of changed files for incremental build. Thus each time one re-compile a file, the other treats it as a changed file and recompile it too.
While CrazyCoder's answer describes how to make them work on separated directory, by changing the sbt compiled classes dir. This answer explain how you can configure Intellij to use sbt for all build, thus only sbt does the compilation. This is a relatively new feature.
Just check the option:
file
> Settings
> Build, Execution, Deployment
> Build Tools
> SBT
> Use SBT shell for build and import
It works at least since intellij version 2017.2.3, and most probably it is an option from the SBT plugin.
For details about this feature, see jetbrains ticket: https://youtrack.jetbrains.com/issue/SCL-10984
IntelliJ IDEA cannot reuse the classes produced by the other build systems because it has its own incremental compiler which tracks the dependencies and builds the caches during the compilation so that it can compile only modified and dependent files when you make a change in the code. When you built with SBT/Maven/Gradle or command line javac, IntelliJ IDEA compiler cache doesn't know about what has changed and which files it should compile, therefore it performs the full rebuild.
A solution would be to use different output directories for IDE and SBT, this way IntelliJ IDEA will rebuild only files modified since the last build in the IDE and your command line SBT build will not trigger a rebuild in the IDE.
This configuration is performed using the sbt-ide-settings plug-in.
Add the following into plugins.sbt (or whatever files you configure the plugins in):
resolvers += Resolver.url("jetbrains-bintray",url("http://dl.bintray.com/jetbrains/sbt-plugins/"))(Resolver.ivyStylePatterns)
addSbtPlugin("org.jetbrains" % "sbt-ide-settings" % "0.1.2")
And here is how to customize the IDE output directory in build.sbt:
ideOutputDirectory in Compile := Some(new File("target/idea/classes"))
ideOutputDirectory in Test := Some(new File("target/idea/test-classes"))
Feel free to change the paths according to your needs.

In an sbt 0.13.7 project, compile the compiler-interfaces without compiling the project code

In a freshly checked out sbt ( 0.3.7 ) project and empty ivy cache, is it possible to trigger compilation of the compiler-interface(s) needed without compiling the project itself? I have poked around but haven't found a way.
Currently if a compiler-interface is required it will be created during compilation of the project. I would like to have this compiled directly in a separate command if possible. This would allow CircleCi to cache it saving 1-3 minutes with every build because it could be cached in the dependencies section of the circle.yml.
In sbt 0.13.12 compile:compileIncremental seems to do the trick. I ran inspect compile and inspected its dependencies to find the command.

how to compile single file in sbt

I'm doing some refactoring that made compiler temporally give errors in several files. I'd like to work with them one by one (starting with common dependencies) and need some tool to check if modification is correct.
sbt compile is inconvenient because it gives too many errors and spends much time for compiling things that have no good.
I'm searching for a way to compile single file with sbt or a method for extracting sbt side libraries definition to pass them to a normal scalac compiler
There was a similar topic: How to compile just some files with sbt? that turned out to be source code error discussion rather that sbt functionality disclosure.
You could add the following line to build.sbt:
sources in Compile <<= (sources in Compile).map(_ filter(_.name == "Particular.scala"))
Then fix Particular.scala, then edit build.sbt and put the name of the next source file. If you keep the sbt console open, reload will re-read the .sbt file after you modify it.
I just wanted to mention here that I came across sbt-compile-quick-plugin (https://github.com/etsy/sbt-compile-quick-plugin). It does what it says on the tin, just add addSbtPlugin("com.etsy" % "sbt-compile-quick-plugin" % "1.3.0") to your project/plugins.sbt, then you can just start up sbt and run compileQuick /path/to/your/file

How to compile tests with SBT without running them

Is there a way to build tests with SBT without running them?
My own use case is to run static analysis on the test code by using a scalac plugin. Another possible use case is to run some or all of the test code using a separate runner than the one built into SBT.
Ideally there would be a solution to this problem that applies to any SBT project. For example, Maven has a test-compile command that can be used just to compile the tests without running them. It would be great if SBT had the same thing.
Less ideal, but still very helpful, would be solutions that involve modifying the project's build files.
Just use the Test / compile command.
Test/compile works for compiling your unit tests.
To compile integration tests you can use IntegrationTest/compile.
Another hint to continuously compile on every file change: ~Test/compile
We have a build.sbt file that is used for multiple projects. Doing sbt test:compile compiled the tests for every single project and took over 30 minutes.
I found out I can compile only the tests for a specific project named xyz by doing:
sbt xyz/test:compile
Using sbt version 1.5.0 and higher test:compile returns deprecation warning.
Use Test / compile.
(docs)