Аммонит: как использовать другой скрипт из зависимости Айви?
У меня есть Ammonite Script, который я хочу доставить в JAR.
В другом проекте я хочу использовать этот скрипт, но пока безуспешно.
Я пробовал по документации (sol_local_build.sc
):
import $ivy.`mycompany:myproject_2.12:2.1.0-SNAPSHOT`, local_build
@main
def doit():Unit =
println(local_build.curl("http://localhost:8080"))
local_build.sc
находится в сценарии, который я хочу использовать.
Это исключение, которое я получаю:
sol_local_build.sc:2: '.' expected but eof found.
^
3 ответа
Скрипт необходимо компилировать на лету.
Поместите свой скрипт в стандартный проект sbt
внутри каталога, пример имени каталога: "test1"
Поместите свой внешний скрипт (пример имени: "script.sc")
// script.sc
println("Hello world!")
в каталог ресурсов ("test1\src\main\resources\script.sc") проекта test1
Опубликуйте проект локально, т.е. sbt publishLocal
Он публикуется в каталоге ".ivy2\local\default\test1_2.12\0.1-SNAPSHOT\ ... ".
Теперь вы можете использовать следующий скрипт аммонита "test.sc".
Читает "script.sc" из jar в локальном репозитории ivy.
и записывает его в локальный каталог (должен иметь доступ для чтения / записи), а затем выполняет внешний процесс,
который вызывает "интерпретатор" scala и выполняет сценарий.
// test.sc
import $ivy.`default:test1_2.12:0.1-SNAPSHOT`
val scriptCode = scala.util.Try {scala.io.Source.fromResource("script.sc").mkString} getOrElse """Println("Script-file not found!")"""
println("*" * 30)
println(scriptCode)
println("*" * 30)
println()
java.nio.file.Files.write(java.nio.file.Paths.get("script.sc"), scriptCode.getBytes(java.nio.charset.StandardCharsets.UTF_8))
val cmd = Seq("cmd.exe", "/c", "scala", "script.sc")
val output = sys.process.Process(cmd).!!
println(output)
Выполнив скрипт Ammonite REPL, вы получите:
******************************
// script.sc
println("Hello world!")
******************************
Hello world!
Сценарий не обрабатывает ошибки и оставляет файл в рабочем каталоге. Вы можете ускорить выполнение с помощью переключателя компилятора "-savecompiled", т.е.
val cmd = Seq("cmd.exe", "/c", "scala", "-savecompiled", "script.sc")
Затем в рабочем каталоге создается дополнительный файл.jar.
Для полноты я мог бы решить свою проблему следующим образом:
- Просто создайте файл Scala в этом проекте.
- Скопируйте содержимое сценария в объект.
package mycompany.myproject object LocalBuild { def curl(..)... }
- Добавьте зависимости в свой файл sbt (например,
ammonite.ops
) - Используйте это как:
$ivy.`mycompany:myproject_2.12:2.1.0-SNAPSHOT`, mycompany.myproject.LocalBuild @main def doit():Unit = println(LocalBuild.curl("http://localhost:8080"))
Сценарии Scala на самом деле не интерпретируются, но компилируются "под капотом", как и любая обычная программа Scala. Поэтому весь код должен быть доступен во время компиляции, и вы не можете вызывать функцию внутри другого скрипта из jar-файла!
Но у Ammonite есть встроенная многоступенчатая функция. Он компилирует одну часть, выполняет ее, а затем компилирует следующую часть!
Немного улучшенный аммонит-скрипт. Это не безошибочно, но работает.
Может, есть способ лучше вытащить скрипт из банки. Спросите Ли Хаойи!
// test_ammo.sc
// using ammonite ops
// in subdirectoy /test1
// Ammonite REPL:
// import $exec.test1.test_ammo
// @ Ammonite-multi-stage
import $ivy.`default::test1:0.1-SNAPSHOT`
//import scala.util.Properties
import scala.sys.process.Process
val scriptFileName = "script.sc"
write.over(pwd/"test1"/scriptFileName, read(resource(getClass.getClassLoader)/scriptFileName))
val cmd = Seq("cmd.exe", "/c", "scala", scriptFileName)
val output = Process(cmd).!!
println(output)
@
import $exec.script // no .sc suffix
ppp() // is a function inside script.sc
script.sc внутри папки ресурсов проекта, опубликованного локально с помощью "sbt publishLocal":
// script.sc
println("Hello world!")
def ppp() = println("Hello world from ppp!")