Why does Scala script fail if CLASSPATH is set? - scala

I have the following Scala 2.10 script that works fine:
#!/bin/bash
classpath="${CLASSPATH}"
unset CLASSPATH
exec ${SCALA_HOME}/bin/scala -cp "${classpath}" "$0" "$#" 2>&1
!#
import stuff
But when CLASSPATH isn't unset, it fails with stuff like:
$ ./setter-for-catan.scala
./setter-for-catan.scala:12: error: not found: object play
import play.api.libs.json.JsArray
^
one error found
Why is this happening?

The scala script has a modest -debug option.
Use -Ylog-classpath to see what the compiler is using.
Use -nc to say "no compile server daemon".
Use fsc -shutdown to start over.
Package changes are anathema, so unexpected dirs in the path with package names, or old package objects, etc, cause inexplicable build problems.
Use PathResolver to dump what classpath it sees.
An empty directory with your package name can interfere with package discovery.
${SCALA_HOME}/bin/scala -cp "${classpath}" scala.tools.util.PathResolver
${SCALA_HOME}/bin/scala -cp "${classpath}" scala.tools.util.PathResolver some-args
You'll see something like:
apm#mara:~/tmp/scripts$ ./foo.sh
object Environment {
scalaHome = /media/Software/scala-2.10.1 (useJavaClassPath = true)
javaBootClassPath = <1122 chars>
javaExtDirs =
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext
/usr/java/packages/lib/ext
javaUserClassPath = ""
scalaExtDirs =
}
object Defaults {
scalaHome = /media/Software/scala-2.10.1
javaBootClassPath =
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/resources.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/sunrsasign.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jsse.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/charsets.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/netx.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/plugin.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rhino.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jfr.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/classes
/media/Software/scala-2.10.1/lib/akka-actors.jar
/media/Software/scala-2.10.1/lib/jline.jar
/media/Software/scala-2.10.1/lib/scala-actors.jar
/media/Software/scala-2.10.1/lib/scala-actors-migration.jar
/media/Software/scala-2.10.1/lib/scala-compiler.jar
/media/Software/scala-2.10.1/lib/scala-library.jar
/media/Software/scala-2.10.1/lib/scala-partest.jar
/media/Software/scala-2.10.1/lib/scalap.jar
/media/Software/scala-2.10.1/lib/scala-reflect.jar
/media/Software/scala-2.10.1/lib/scala-swing.jar
/media/Software/scala-2.10.1/lib/typesafe-config.jar
scalaLibDirFound = Some(/media/Software/scala-2.10.1/lib)
scalaLibFound = /media/Software/scala-2.10.1/lib/scala-library.jar
scalaBootClassPath =
scalaPluginPath = /media/Software/scala-2.10.1/misc/scala-devel/plugins
}
COMMAND: 'scala some-args'
RESIDUAL: 'scala some-args'

There may be some funky state leftover from the compiler daemon. Try fsc -shutdown or scala -nc to reset the daemon.

Related

Test initialCommands in SBT

I have a subproject in my build.sbt with a rather long setting for initialCommands, comprising a list of imports and some definitions. I'd like to test this as part of regular CI, because otherwise I won't notice breaking changes after refactoring code. It is not clear to me how to do so.
Just running sbt console doesn't seem to cut it, because there is always a "successful" exit code even when code doesn't compile.
Moving the code out into an object defined in a special source file won't help because I need the list of imports to be present (and I don't want to cakeify my whole code base).
Moving the code out into a source file and then loading that with :load also always gives a successful exit code.
I found out about scala -e but that does strange things on my machine (see the error log below).
This is Scala 2.12.
$ scala -e '1'
cat: /release: No such file or directory
Exception in thread "main" java.net.UnknownHostException: <my-host-name-here>: <my-host-name-here>: Name or service not known
You could generate a file and run it like any other test file:
(sourceGenerators in Test) += Def.task {
val contents = """object TestRepl {
{{}}
}""".replace("{{}}", (initialCommands in console).value)
val file = (sourceManaged in Test).value / "repltest.scala"
IO.write(file, contents)
Seq(file)
}.taskValue

How can I change Scala script's directory?

I want use Scala like Python, so I install REPL in Sublime Text(Os is win8)
Everytime in REPL, I have to
scala> :load <my file>
, so I think it's inconvenient.
And I can't change
scala> :settings -d <路径名>
in Chinese directory.
I'm confused whether I can't change Scala script's directory with non-english language.
Thanks a lot!
If you use sbt then you can define initial commands when you launch the console.
yourproject/build.sbt:
// build.sbt
name := "initial-commands-example"
initialCommands := "import Foo._"
yourproject/script.scala:
// script.scala
object Foo {
def hello(name: String) = s"hello $name"
val msg = hello("world")
}
Inside yourproject, run sbt console, and you will have everything in Foo available inside that repl. See sbt initialCommands docs for more information.

How to work with Scala and Jcurses?

I want to use Jcurses with Scala on a 64-bit Ubuntu.
Unfortunately i didn't find any tutorial about this subject. Can anybody help me!
My test program "testjcurses.scala"
import jcurses.system._
object TestJcurses {
def main(args:Array[String]) {
println("okay")
Toolkit.init()
}
}
I processed it the following way:
fsc -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src -d . -Djava.library.path=~/software/Java/jcurses/lib testjcurses.scala
scala -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
The result is:
okay
java.lang.NullPointerException
at jcurses.system.Toolkit.getLibraryPath(Toolkit.java:97)
at jcurses.system.Toolkit.<clinit>(Toolkit.java:37)
at TestJcurses$.main(testjcurses.scala:9)
at TestJcurses.main(testjcurses.scala)
..........
Can anybody help me?
Unfortunately you can't use ~ in bash like that — ~ is expanded to your home dir only right after an (unquoted) space (technically, at the beginning of a bash word, but "after a space" is the simple version). Look how your command line is expanded:
$ echo scala -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
scala -cp /Users/pgiarrusso/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
As you can see, the ~ is there in the expanded version, and will arrive unchanged to your program, which will be unable to interpret it as anything since tilde expansion is a job for the shell.
Also, you shouldn't need the source directory ~/software/Java/jcurses/src in your classpath (since source files aren't needed to run the program). So try:
scala -cp ~/software/Java/jcurses/lib/jcurses.jar:. -Djava.library.path=$HOME/software/Java/jcurses/lib TestJcurses

How to execute Scala script from Gradle?

I have a Scala script that looks something like:
#!/bin/sh
PATH=${SCALA_HOME}:${PATH}
exec scala "$0" "$#"
!#
Console.println("Hello, world!")
Is there some way in Gradle to set the version of Scala to be used, have it implicitly set SCALA_HOME, and execute the script?
There is no built-in feature for this. The way to tackle this is to declare two tasks: A Copy task that downloads the Scala distribution and unpacks it to a local directory, and an Exec task that sets the SCALA_HOME environment variable to the copy task's output directory and executes your script.
Here is an example of executing Scala from Gradle. It is a nascent attempt to build a plugin using Scalafmt. Of note is how nasty it is to use static values.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.geirsson:scalafmt-core_2.11:0.4.2'
}
}
task scalafmt << {
String target = "object FormatMe { List(Split(Space, 0).withPolicy(SingleLineBlock(close)), Split(Newline, 1).withPolicy{ case Decision(t#FormatToken(_, `close`, _), s) => Decision(t, List(Split(Newline, 0)))}.withIndent(2, close, Right)) }"
def config = org.scalafmt.config.ScalafmtConfig$.MODULE$.default
def range = scala.collection.immutable.Set$EmptySet$.MODULE$
println org.scalafmt.Scalafmt.format(target, config, range).formattedCode()
}
I know this is not quite on topic but I couldn't find anywhere else to put this and I hope it is of some value to people who ended up here for the same reason I did.
Gradle has an Exec task in which you can set the environment to be passed to the new process. You could pass SCALA_HOME through that.

How to start a Scala method from command line?

This question may sound a bit stupid, but I couldn't figure out, how to start a Scala method from the command line.
I compiled the following file Test.scala :
package example
object Test {
def print() {
println("Hello World")
}
}
with scalac Test.scala.
Then, I can run the method print with scala in two steps:
C:\Users\John\Scala\Examples>scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) Client VM, Java 1.6.0_32).
Type in expressions to have them evaluated.
Type :help for more information.
scala> example.Test.print
Hello World
But what I really like to do is, to run the method directly from the command line with one command like scala example.Test.print.
How can I achieve this goal ?
UPDATE:
Suggested solution by ArikG does not work for me - What I am missing ?
C:\Users\John\Scala\Examples>scala -e 'example.Test.print'
C:\Users\John\AppData\Local\Temp\scalacmd1874056752498579477.scala:1: error: u
nclosed character literal
'example.Test.print'
^
one error found
C:\Users\John\Scala\Examples>scala -e "example.Test.print"
C:\Users\John\AppData\Local\Temp\scalacmd1889443681948722298.scala:1: error: o
bject Test in package example cannot be accessed in package example
example.Test.print
^
one error found
where
C:\Users\John\Scala\Examples>dir example
Volume in drive C has no label.
Volume Serial Number is 4C49-8C7F
Directory of C:\Users\John\Scala\Examples\example
14.08.2012 12:14 <DIR> .
14.08.2012 12:14 <DIR> ..
14.08.2012 12:14 493 Test$.class
14.08.2012 12:14 530 Test.class
2 File(s) 1.023 bytes
2 Dir(s) 107.935.760.384 bytes free
UPDATE 2 - Possible SOLUTIONs:
As ArikG correctly suggested, with scala -e "import example.Test._; print" works well with Windows 7.
See answer of Daniel to get it work without the import statement
Let me expand on this solution a bit:
scala -e 'example.Test.print'
Instead, try:
scala -cp path-to-the-target-directory -e 'example.Test.print'
Where the target directory is the directory where scala used as destination for whatever it compiled. In your example, it is not C:\Users\John\Scala\Examples\example, but C:\Users\John\Scala\Examples. The directory example is where Scala will look for classes belonging to the package example.
This is why things did not work: it expected to find the package example under a directory example, but there were no such directory under the current directory in which you ran scala, and the classfiles that were present on the current directory were expected to be on the default package.
The best way to do this is to extend App which is a slightly special class (or at least DelayedInit which underlies it is):
package example
object Test extends App {
println("Hello World")
}
It's still possible to add methods to this as well, the body of the object is executed on startup.
Here you go:
scala -e 'example.Test.print'