Spec-Zone.ru › Kotlin 1.9

Начало работы с пользовательским сценарием Kotlin — учебное пособие

Сценарии Kotlin находятся в Экспериментальной стадии. Они могут быть удалены или изменены в любое время. Используйте их только для оценочных целей. Мы ценим ваши отзывы об этом на YouTrack.

Сценарии Kotlin — это технология, которая позволяет выполнять код Kotlin в виде сценариев без предварительной компиляции или упаковки в исполняемые файлы.

Для обзора сценариев Kotlin с примерами ознакомьтесь с выступлением Реализация Gradle Kotlin DSL Родриго Оливейры с KotlinConf'19.

В этом руководстве вы создадите проект Kotlin со сценариями, который будет выполнять произвольный код Kotlin с зависимостями Maven. Вы сможете выполнять сценарии следующего вида:

@file:Repository("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.3")

import kotlinx.html.*
import kotlinx.html.stream.*
import kotlinx.html.attributes.*

val addressee = "World"

print(
    createHTML().html {
        body {
            h1 { +"Hello, $addressee!" }
        }
    }
)

Указанная зависимость Maven (kotlinx-html-jvm в этом примере) будет разрешена из указанного репозитория Maven или локального кэша во время выполнения и использоваться в остальной части сценария.

Структура проекта

Минимальный проект Kotlin со сценариями состоит из двух частей:

  • Определение сценария — набор параметров и настроек, определяющих, как этот тип сценария должен распознаваться, обрабатываться, компилироваться и выполняться.

  • Хост сценариев — приложение или компонент, который обрабатывает компиляцию и выполнение сценариев — фактически запускает сценарии этого типа.

Учитывая это, лучше разделить проект на два модуля.

Прежде чем начать

Загрузите и установите последнюю версию IntelliJ IDEA.

Создание проекта

  1. В IntelliJ IDEA выберите Файл | Новый | Проект.

  2. В панели слева выберите Новый проект.

  3. Назовите новый проект и измените его расположение, если необходимо.

    Выберите флажок Создать хранилище Git, чтобы поместить новый проект под систему контроля версий. Вы сможете сделать это позже в любое время.

  4. Из списка Язык выберите Kotlin.

  5. Выберите систему сборки Gradle.

  6. Из списка JDK выберите JDK, который вы хотите использовать в проекте.

    • Если JDK установлен на вашем компьютере, но не определён в IDE, выберите Добавить JDK и укажите путь к домашнему каталогу JDK.

    • Если у вас нет необходимого JDK на компьютере, выберите Загрузить JDK.

  7. Выберите язык Kotlin или Gradle для Gradle DSL.

  8. Нажмите Создать.

Create a root project for custom Kotlin scripting

Добавление модулей сценариев

Теперь у вас есть пустой проект Kotlin/JVM Gradle. Добавьте необходимые модули, определение сценария и хост сценариев:

  1. В IntelliJ IDEA выберите Файл | Новый | Модуль.

  2. В панели слева выберите Новый модуль. Этот модуль будет определением сценария.

  3. Назовите новый модуль и измените его расположение, если необходимо.

  4. Из списка Язык выберите Java.

  5. Выберите систему сборки Gradle и Kotlin для Gradle DSL, если хотите написать скрипт сборки на Kotlin.

  6. В качестве родительского модуля выберите корневой модуль.

  7. Нажмите Создать.

    Create script definition module
  8. В файле build.gradle(.kts) модуля удалите version плагина Kotlin Gradle. Он уже находится в скрипте сборки корневого проекта.

  9. Повторите предыдущие шаги ещё раз, чтобы создать модуль для хоста сценариев.

Структура проекта должна быть следующей:

Custom scripting project structure

Пример такого проекта и дополнительные примеры сценариев Kotlin можно найти в репозитории kotlin-script-examples GitHub.

Создание определения сценария

Сначала определите тип сценария: что разработчики могут написать в сценариях этого типа и как он будет обрабатываться. В этом руководстве это включает поддержку аннотаций @Repository и @DependsOn в сценариях.

  1. В модуле определения сценария добавьте зависимости от компонентов сценариев Kotlin в блок dependencies файла build.gradle(.kts). Эти зависимости предоставляют API, которые вам понадобятся для определения сценария:

    dependencies {
        implementation("org.jetbrains.kotlin:kotlin-scripting-common")
        implementation("org.jetbrains.kotlin:kotlin-scripting-jvm")
        implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies")
        implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies-maven")
        // coroutines dependency is required for this particular definition
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1") 
    }
    
    dependencies {
        implementation 'org.jetbrains.kotlin:kotlin-scripting-common'
        implementation 'org.jetbrains.kotlin:kotlin-scripting-jvm'
        implementation 'org.jetbrains.kotlin:kotlin-scripting-dependencies'
        implementation 'org.jetbrains.kotlin:kotlin-scripting-dependencies-maven'
        // coroutines dependency is required for this particular definition
        implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1'
    
    }
    
  2. Создайте директорию src/main/kotlin/ в модуле и добавьте файл Kotlin-исходника, например, scriptDef.kt.

  3. В scriptDef.kt, создайте класс. Он будет базовым классом для сценариев этого типа, поэтому объявите его abstract или open.

    // abstract (or open) superclass for scripts of this type
    abstract class ScriptWithMavenDeps
    

    Этот класс также послужит ссылкой на определение сценария позже.

  4. Чтобы сделать класс определением сценария, отметьте его аннотацией @KotlinScript. Передайте два параметра в аннотацию:

    • fileExtension — строка, заканчивающаяся на .kts, которая определяет расширение файла для сценариев этого типа.

    • compilationConfiguration — класс Kotlin, который расширяет ScriptCompilationConfiguration и определяет особенности компиляции для этого определения сценария. Вы создадите его на следующем шаге.

     // @KotlinScript annotation marks a script definition class
     @KotlinScript(
         // File extension for the script type
         fileExtension = "scriptwithdeps.kts",
         // Compilation configuration for the script type
         compilationConfiguration = ScriptWithMavenDepsConfiguration::class
     )
     abstract class ScriptWithMavenDeps
    
     object ScriptWithMavenDepsConfiguration: ScriptCompilationConfiguration()
    

    В этом руководстве мы предоставляем только работающий код без объяснения API сценариев Kotlin. Вы можете найти тот же код с подробным объяснением на GitHub.

  5. Определите конфигурацию компиляции сценария, как показано ниже.

     object ScriptWithMavenDepsConfiguration : ScriptCompilationConfiguration(
         {
             // Implicit imports for all scripts of this type
             defaultImports(DependsOn::class, Repository::class)
             jvm {
                 // Extract the whole classpath from context classloader and use it as dependencies
                 dependenciesFromCurrentContext(wholeClasspath = true) 
             }
             // Callbacks
             refineConfiguration {
                 // Process specified annotations with the provided handler
                 onAnnotations(DependsOn::class, Repository::class, handler = ::configureMavenDepsOnAnnotations)
             }
         }
     )
    

    Функция configureMavenDepsOnAnnotations выглядит следующим образом:

     // Handler that reconfigures the compilation on the fly
     fun configureMavenDepsOnAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> {
         val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
             ?: return context.compilationConfiguration.asSuccess()
         return runBlocking {
             resolver.resolveFromScriptSourceAnnotations(annotations)
         }.onSuccess {
             context.compilationConfiguration.with { 
                 dependencies.append(JvmDependency(it))
             }.asSuccess()
         }
     }
    
     private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver())
    

    Полный код можно найти здесь.

END_OF_DOCUMENT_MARKER

Создание хоста сценариев

Следующим шагом является создание хоста сценариев – компонента, обрабатывающего выполнение сценариев.

  1. В модуле хоста сценариев добавьте зависимости в блок dependencies в build.gradle(.kts):

    • Компоненты Kotlin для сценариев, предоставляющие необходимые для хоста сценариев API

    • Модуль определения сценариев, созданный ранее

    dependencies {
        implementation("org.jetbrains.kotlin:kotlin-scripting-common")
        implementation("org.jetbrains.kotlin:kotlin-scripting-jvm")
        implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host")
        implementation(project(":script-definition")) // the script definition module
    }
    
    dependencies {
        implementation 'org.jetbrains.kotlin:kotlin-scripting-common'
        implementation 'org.jetbrains.kotlin:kotlin-scripting-jvm'
        implementation 'org.jetbrains.kotlin:kotlin-scripting-jvm-host'
        implementation project(':script-definition') // the script definition module
    }
    
  2. Создайте директорию src/main/kotlin/ в модуле и добавьте Kotlin-файл, например, host.kt.

  3. Определите функцию main для приложения. В ее теле проверьте, что у нее один аргумент – путь к файлу сценария – и выполните сценарий. Вы определите выполнение сценария в отдельной функции evalFile на следующем шаге. На данный момент объявите ее пустой.

    main может выглядеть так:

     fun main(vararg args: String) {
         if (args.size != 1) {
             println("usage: <app> <script file>")
         } else {
             val scriptFile = File(args[0])
             println("Executing script $scriptFile")
             evalFile(scriptFile)
         }
     }
    
  4. Определите функцию оценки сценария. Здесь вы будете использовать определение сценария. Получите его, вызвав createJvmCompilationConfigurationFromTemplate с классом определения сценария в качестве параметра типа. Затем вызовите BasicJvmScriptingHost().eval, передав ей код сценария и его конфигурацию компиляции. eval возвращает экземпляр ResultWithDiagnostics, поэтому установите его в качестве типа возвращаемого значения функции.

     fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
         val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<ScriptWithMavenDeps>()
         return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, null)
     }
    
  5. Измените функцию main для вывода информации о выполнении сценария:

     fun main(vararg args: String) {
         if (args.size != 1) {
             println("usage: <app> <script file>")
         } else {
             val scriptFile = File(args[0])
             println("Executing script $scriptFile")
             val res = evalFile(scriptFile)
             res.reports.forEach {
                 if (it.severity > ScriptDiagnostic.Severity.DEBUG) {
                     println(" : ${it.message}" + if (it.exception == null) "" else ": ${it.exception}")
                 }
             }
         }
     }
    

Полный код вы можете найти здесь

Выполнение сценариев

Чтобы проверить работу вашего хоста сценариев, подготовьте сценарий для выполнения и конфигурацию запуска.

  1. Создайте файл html.scriptwithdeps.kts с указанным ниже содержимым в корневом каталоге проекта:

    @file:Repository("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
    @file:DependsOn("org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.3")
    
    import kotlinx.html.*; import kotlinx.html.stream.*; import kotlinx.html.attributes.*
    
    val addressee = "World"
    
    print(
        createHTML().html {
            body {
                h1 { +"Hello, $addressee!" }
            }
        }
    )
    

    Он использует функции из библиотеки kotlinx-html-jvm, на которую есть ссылка в аргументе аннотации @DependsOn.

  2. Создайте конфигурацию запуска, которая запускает хост сценариев и выполняет этот файл:

    1. Откройте host.kt и перейдите к функции main. У нее есть значок Запуск слева.

    2. Щелкните правой кнопкой мыши значок и выберите Изменить конфигурацию запуска.

    3. В диалоговом окне Создание конфигурации запуска добавьте имя файла сценария в Аргументы программы и нажмите OK.

      Scripting host run configuration
  3. Запустите созданную конфигурацию.

Вы увидите, как сценарий выполняется, разрешая зависимость от kotlinx-html-jvm в указанном репозитории и выводя результаты вызова его функций:

<html>
  <body>
    <h1>Hello, World!</h1>
  </body>
</html>

Разрешение зависимостей может занять некоторое время при первом запуске. Последующие запуски будут завершаться гораздо быстрее, так как они используют загруженные зависимости из локального репозитория Maven.

Что дальше?

После создания простого проекта Kotlin для сценариев найдите дополнительную информацию по этой теме:

  • Прочитайте Kotlin scripting KEEP

  • Просмотрите другие примеры Kotlin для сценариев

  • Посмотрите презентацию Реализация Gradle Kotlin DSL Rodrigo Oliveira

Последнее изменение: 11 мая 2023 г.
Обзор коллекций

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/custom-script-deps-tutorial.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API