sbt key that corresponds to command that I type in - sbt

I want to make my tests run every time I type universal:package-zip-tarball. I know that to do this, I have to put something like
someKey <<= someKey dependsOn (test in Test)
in my project/Build.scala, where someKey is the key that provides the task I want to depend on the test run, in this case, universal:package-zip-tarball.
But my generic question is: how do I find out what someKey should be?
Note that this is a Play framework project, and I don't even know if universal:package-zip-tarball is provided by Play, or by some other sbt plugin.
Is there any way sbt can just tell me, without me having to go searching for the source code repository containing the relevant code?

Use the inspect command:
$ inspect universal:package-zip-tarball
[...]
[info] Defined at:
[info] (com.typesafe.sbt.packager.universal.UniversalPlugin)
UniversalPlugin.scala:73
This is actually the location of the definition of the code of the task, but this is close enough to help, because it lets us find the key (the key will be in the same sbt plugin).
From this we can find out that the key is:
com.typesafe.sbt.packager.universal.Keys.packageZipTarball
Unfortunately, just substituting this in doesn't work - it says:
[error] Reference to undefined setting:
[error]
[error] my-project/*:packageZipTarball from my-project/*:packageZipTarball
[error] Did you mean my-project/universal-docs:packageZipTarball ?
[error]
[error] Use 'last' for the full log.
So to fix this, the only thing remaining is to translate the universal: prefix. It is in fact this:
packageZipTarball in Universal <<= packageZipTarball in Universal dependsOn (test in Test)
but it just needs an extra import to make it compile:
import com.typesafe.sbt.SbtNativePackager._
(In this case, SbtNativePackager is the main plugin object, I think. Other plugins might require importing something else, to translate such a prefix.)

Related

SBT support for custom ivy module status?

In my SBT build I have a dependency on an ivy artifact that makes use of a custom module status. This causes the following error in SBT:
[error] (*:update) sbt.ResolveException: unresolved dependency: my-org#myapp-core_2.11;1.0: java.text.ParseException: inconsistent module descriptor file found in 'http://artifacts.myorg.com/libs-snapshots-local/myapp-core_2.11/1.0/myapp-ivy.xml': bad status: 'snapshot';
I can work around this by telling SBT to use an external ivy settings, like so:
externalIvySettings(baseDirectory(_ / "ivySettings.xml"))
And then create an ivySettings.xml containing the following:
<statuses default="release">
<status name="release" integration="false"/>
<status name="snapshot" integration="false"/>
</statuses>
But surely there must be a better way? The problem with this work around is that now all my settings (such as resolvers) have to be in the ivy file too, because (IFAIK) it's all or nothing when you use externalIvySettings.
Is there a way to specify a set of custom statuses within my build.sbt? Or alternatively is there a way to tell sbt to combine external ivy settings with the ones it generates from the build.sbt.
Since specifying custom module statuses is a valid thing to do in ivy, this should really be supported in sbt too.
This is because for some repositories, they use non-standard status which fails the consistency check. We addressed this by constructing the customized resolver which doesn't do consistency check. You can also construct resolver with the custom status using the same approach. The following is the working snippet.
resolvers += {
val resolver = new org.apache.ivy.plugins.resolver.IBiblioResolver
resolver.setName("Custom Ivy Snapshots")
resolver.setRoot("http://Custom/snapshots/")
val settings = new org.apache.ivy.core.settings.IvySettings()
settings.setVariable("ivy.local.default.ivy.pattern", Pattern)
settings.setVariable("ivy.local.default.artifact.pattern", Pattern)
resolver.setSettings(settings)
resolver.setM2compatible(true)
resolver.setCheckconsistency(false)
new RawRepository(resolver)
}

sbt cross configuration dependencies

what is the reason SBT won't allow me to have dependencies between different configurations of different projects in a multi-project build?
consider the following setup in the main build.sbt file:
lazy val domain: Project = project in file("domain") dependsOn(testUtils % "test->test")
lazy val testUtils: Project = project in file("testUtils") dependsOn(domain % "compile->test")
...
I would want to write all my test helpers in testUtils, and have each of the other projects' test code to be clean test logic without the (sometimes duplicated among different projects) boilerplate of the aiding methods.
SBT is forcing me to put the : Project type, since it complains the value is "recursive". and upon reloading, I get:
...
at $281429c805669a7befa4$.domain(build.sbt:142)
at $281429c805669a7befa4$.testUtils$lzycompute(build.sbt:144)
at $281429c805669a7befa4$.testUtils(build.sbt:144)
at $281429c805669a7befa4$.domain$lzycompute(build.sbt:142)
at $281429c805669a7befa4$.domain(build.sbt:142)
[error] java.lang.StackOverflowError
[error] Use 'last' for the full log.
is there a way around this? or should I write test-related logic in each module test, even at the cost of getting the code less organize, many "test->test" dependencies, etc'...

SBT console encoding for test results

I have an SBT + Scalatest project. Now my tests log in console something like this:
[info] - should do something *** FAILED ***
[info] java.lang.Exception: ╧ЁштхЄ!
That's not very useful of cause.. Exception text is in Cyrillic so I have to set cp866 charset on console stream to display it correctly.
I've tried
Console.setOut(new PrintStream(System.out, true, "cp866"))
But SBT ignores it. It seems that SBT constructs it's own stream for logging various messages, but I can't find where and how to alter it..
There is a way to add custom logger, but it's an overkill.
I've found a solution.
I can create a custom LogManager
val customLogManager = LogManager.defaultManager(ConsoleOut.printStreamOut(new java.io.PrintStream(System.out, true, "cp866")))
And set it in project settings:
logManager := customLogManager
Though, I'm not sure if it is the best solution. One flaw is that you have to provide logManager setting for every project. Inheriting it from build settings doesn't work for some reason.

SBT setting fallback search path

How are you doing?
I did the following in SBT console:
inspect version
And I get something like the following:
[info] Delegates:
[info] *:version
[info] {.}/*:version
[info] */*:version
So, actually, what's the difference between the last two??? I read and read the documentation but can't seem to make any difference to me. One is ThisBuild (a.k.a. entire build, a.k.a. {.}) while the other one is Global.
Why does {.} in the project axis has precedence over * in the project axis?
The values {.} and * looks pretty much the same to me..
Thanks!!!!
The order of the last two in:
*:version -> try current project
{.}/*:version -> try this build
*/*:version -> try global
says that whatever version you specified in this build, you want that to override anything that was possibly defined in Global.
Example: Key "version"
For Global scope it was defined in Defaults.scala with value "0.1-SNAPSHOT".
For your projects in this build you might want to overwrite that with:
version in ThisBuild := "3.0.1"
So, because {.}/*:version has precedence over /:version, whenever you get "version" in your projects, you fetch "3.0.1" instead of "0.1-SNAPSHOT".

How do you do develop an SBT project, itself?

Background: I've got a Play 2.0 project, and I am trying to add something to do aspectj weaving using aspects in a jar on some of my classes (Java). (sbt-aspectj doesn't seem to do it, or I can't see how). So I need to add a custom task, and have it depend on compile. I've sort of figured out the dependency part. However, because I don't know exactly what I'm doing, yet, I want to develop this using the IDE (I'm using Scala-IDE). Since sbt projects (and therefore Play projects) are recursively defined, I assumed I could:
Add the eclipse plugin to the myplay/project/project/plugins.sbt
Add the sbt main jar (and aspectj jar) to myplay/project/project/build.sbt:
libraryDependencies ++= Seq(
"org.scala-sbt" % "main" % "0.12.2",
"aspectj" % "aspectj-tools" % "1.0.6"
)
Drop into the myplay/project
Run sbt, run the eclipse task, then import the project into eclipse as a separate project.
I can do this, though the build.scala (and other scala files) aren't initially considered source, and I have to fiddle with the build path a bit. However, even though I've got the sbt main defined for the project, both eclipse IDE and the compile task give errors:
> compile
[error] .../myplay/project/Build.scala:2: not found: object keys
[error] import keys.Keys._
[error] ^
[error] .../myplay/project/SbtAspectJ.scala:2: object Configurations is not a member of package sbt
[error] import sbt.Configurations.Compile
[error] ^
[error] .../myplay/project/SbtAspectJ.scala:3: object Keys is not a member of package sbt
[error] import sbt.Keys._
[error] ^
[error] three errors found
The eclipse project shows neither main nor aspectj-tools in its referenced-libraries. However, if I give it a bogus version (e.g. 0.12.4), reload fails, so it appears to be using
the dependency.
So,...
First: Is this the proper way to do this?
Second: If so, why aren't the libs getting added.
(Third: please don't let this be something dumb that I missed.)
If you are getting the object Keys is not a member of package sbt error, then you should check that you are running sbt from the base directory, and not the /project directory.
sbt-aspectj
sbt-aspectj doesn't seem to do it, or I can't see how.
I think this is the real issue. There's a plugin already that does the work, so try making it work instead of fiddling with the build. Using plugins from build.scala is a bit tricky.
Luckily there are sample projects on github:
import sbt._
import sbt.Keys._
import com.typesafe.sbt.SbtAspectj.{ Aspectj, aspectjSettings, compiledClasses }
import com.typesafe.sbt.SbtAspectj.AspectjKeys.{ binaries, compileOnly, inputs, lintProperties }
object SampleBuild extends Build {
....
// precompiled aspects
lazy val tracer = Project(
"tracer",
file("tracer"),
settings = buildSettings ++ aspectjSettings ++ Seq(
// stop after compiling the aspects (no weaving)
compileOnly in Aspectj := true,
// ignore warnings (we don't have the sample classes)
lintProperties in Aspectj += "invalidAbsoluteTypeName = ignore",
// replace regular products with compiled aspects
products in Compile <<= products in Aspectj
)
)
}
How do you do develop an SBT project, itself?
If you're interested in hacking on the build still the first place to go is the Getting Started guide. Specifically, your question should be answered in .scala Build Definition page.
I think you want your build to utilize "aspectj" % "aspectj-tools" % "1.0.6". If so it should be included in myplay/project/plugins.sbt, and your code should go into myplay/project/common.scala or something. If you want to use IDE, you have have better luck with building it as a sbt plugin. That way your code would go into src/main/scala. Check out sbt/sbt-aspectj or sbt/sbt-assembly on example of sbt plugin structure.

Resources