Is there somewhere a guide to SBT for non-Scala programmers?

Viewed 1607

Someday, I'd like to learn Scala. What I see about the language from people who like it is very encouraging.

Today, though, is not that day. Today, I'd just like to make some changes to my team's build file. Unfortunately, this build file was put together with SBT, and is nearly incomprehensible.

My main issue is that it appears to me that SBT introduces some huge collection of new operators that do things with strings and lists to create some sort of sbt object. For example, in sbt:

"args4j" % "args4j" % "2.0.12"

Apparently is actually defined; however, I can't even tell what type it is at the scala repl, since at the repl I get the sensible error:

scala> val tstcrap = "args4j" % "args4j" % "2.0.12"
<console>:6: error: value % is not a member of java.lang.String
       val tstcrap = "args4j" % "args4j" % "2.0.12"

I get this error even after setting up the classpath to include the sbt-launch.jar file and doing import sbt._.

Likewise, I'm dealing with stuff like this:

 val jarSources = (descendents(classesOutput ##, "*") ---
                  assemblyExclude(classesOutput ##))

What's that ## operator, what's that --- doing, and more importantly what is the type of this expression? Are all these new operators documented somewhere, and is there some way to get a scala repl that's using the same language as is used in the sbt build files?

Looking at this sbt file reminds me of trying to decipher perl without ever reading any of the relevant man pages. (Not a recommended activity)

Update: After looking at the links in the answer below, and looking at other questions and answers tagged sbt, I've come across the major piece of scala knowledge that I was missing: scala allows one to define implicit conversions that will be invoked before methods are resolved. In this case, sbt defines inside the ManagedProject trait, an implicit conversion from String to the private class sbt.GroupID, so that

"a" % "b"

Is really something like

(new GroupID("a")) % "b"

I imagine the resolution order and other rules around implicit conversions must get very complicated; it almost reminds me of the nightmares you can introduce in C++ with operator overloading when done through non-member functions.

2 Answers
Related