VirtusLab / scala-cli

Scala CLI is a command-line tool to interact with the Scala language. It lets you compile, run, test, and package your Scala code (and more!)
https://scala-cli.virtuslab.org
Apache License 2.0
529 stars 125 forks source link

java 9+ arguments file not yet supported #2958

Open philwalk opened 1 month ago

philwalk commented 1 month ago

Is your feature request related to a problem? Please describe. A better way to add extra jars to the a script classpath is needed, equivalent to the "arguments file" feature of java 9+.

Describe the solution you'd like The current support for adding jars that aren't in a repository to a script classpath is restrictive. It also prevents such scripts from being os-portable, because it requires the path.separator to be imbedded in the script.

The following script successfully adds a jar to the classpath:

#!/usr/bin/env -S scala-cli shebang --extra-jars C:/Users/username/lib/privateJarA.jar
//> using scala "3.4.2"
sys.props("java.class.path").split(psep).foreach { println }
def psep: String = sys.props("path.separator")

This approach works for jar paths that are sufficiently short, but in general, it's inflexible, and it requires a non-portable classpath.

The old script runner supports using an arguments file to get the classpath argument.

#!/usr/bin/env -S scala @/opt/ue/argsFile
def main(args: Array[String]): Unit =
  def psep: String = sys.props("path.separator")
  sys.props("java.class.path").split(psep).foreach { println }

It's succinct, flexible and scalable. It moves the path.separator from the script to a local path, resulting in an os-portable script.

Describe alternatives you've considered I tried to pass the arguments file as a javaOpt, but it quietly failed (it didn't modify the classpath):

#!/usr/bin/env -S scala-cli shebang
//> using scala "3.4.2"
//> using javaOpt @/opt/ue/argsFile
def psep: String = sys.props("path.separator")
sys.props("java.class.path").split(psep).foreach { println }
philwalk commented 1 week ago

BTW, I don't think this is a windows-only issue, this feature is supported by the jvm in Linux/osx/Windows, etc.

philwalk commented 1 week ago

I've been experimenting with trying to run my scripts with the scala-cli based release candidate scala 3.5.0-RC2. Ideally it will eventually be possible to get most or all of my currently 938 scripts working with little or no changes. My guess is that when this feature is implemented, it will get me 90% of the way there.

Here's a very short script that works with scala3-3.4.2:

#!/usr/bin/env -S scala @/opt/ue/atFile.out
printf("%s\n", vast.db.Sipro.activeDatabase)

Here is the modified version that works with scala3-3.5.0-RC2:

#!/usr/bin/env -S scala -cp C:/Users/philwalk/.ivy2/local/org.vastblue/vast_3/0.9.16/jars/vast_3.jar;C:/Users/philwalk/AppData/Local/https/repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3.jar;C:/Users/philwalk/.ivy2/local/org.vastblue/pallet_3/0.10.12/jars/pallet_3.jar;C:/Users/philwalk/.ivy2/local/org.vastblue/unifile_3/0.3.3/jars/unifile_3.jar
printf("%s\n", vast.db.Sipro.activeDatabase)

Because these scripts run on Windows, Linux and OsX, it's not possible to embed the classpath in the shebang line, due to non-portable path-separator values in the classpath.