如何从 gradle 已经有主项目的项目中 运行 Kotlin 脚本?

How to run a Kotlin script from within a gradle project that already has a main?

我有一个名为 Application.kt 的 Ktor 项目。

布局是这样的

.
└── com
    └── myProject
        ├── Application.kt
        ├── Testing.kt
        ├── api
        │   ├── Routes.kt
        │   └── routes
        │       ├── NewRoutes.kt
        │       ├── OpenApiRoutes.kt
        │       └── OldRoutes.kt
        ├── data
        │   ├── Mongo.kt
        │   ├── model
        │   │   ├── model1
        │   │   │   ├── Model1.kt
        │   │   └── model2
        │   │       ├── Model2.kt
        │   └── repository
        │       ├── MongoRepository.kt
        │       └── Repository.kt

但现在我有一个脚本,我想 运行 作为 Kubernetes init 容器的一部分,文件看起来像这样

import com.myProject.data.Mongo
import org.bson.BsonDocument
import org.litote.kmongo.formatJson

class Testing {
  suspend fun test() {
      return whatever
  }

  suspend fun test2() {
     return whatever2
  }
}

suspend fun main() {
  val create = Testing()
  create.test()
  create.test2()
}

我试过 运行ning ./gradlew testing 我在我的 build.gradle 中这样定义:

task testing( type: JavaExec) {
  main = 'com.myProject.Testing'
}

但是没有用,有没有人有什么想法?

当尝试 运行 使用上面的 gradle 命令时,我得到错误 Could not find or load main class Testing

我的build.gradle

import org.gradle.api.tasks.testing.logging.TestExceptionFormat

buildscript {
    repositories {
        jcenter()
        maven { url 'https://jitpack.io' }
    }
    
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
    }
}


task testing( type: JavaExec) {
  main = 'com.myProject.Testing'
  classpath = sourceSets.main.runtimeClasspath
}


tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

apply plugin: "java"
apply plugin: 'kotlin'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'jacoco'

group 'com.myProject'
version '0.0.1'
mainClassName = "io.ktor.server.netty.EngineMain"

shadowJar {
    manifest {
        attributes 'Main-Class': mainClassName
    }
}

sourceSets {
    main.kotlin.srcDirs = main.java.srcDirs = ['src']
    test.kotlin.srcDirs = test.java.srcDirs = ['test']
    main.resources.srcDirs = ['resources']
    test.resources.srcDirs = ['testresources']
}

repositories {
    mavenCentral()    
    jcenter()
    maven { url 'https://jitpack.io' }
    maven { url 'https://kotlin.bintray.com/ktor' }
}

您可以使用以下格式来定义任务:

task <task-name>(type: JavaExec) {
    main = '[<package>.]<file-class>'
    classpath = sourceSets.main.runtimeClasspath
}

其中 <task-name> — Gradle 任务的名称,<package> — 您的脚本所在的包 class,<file-class> — 没有扩展名的大写文件名+ Kt 后缀。

例如,如果我调用任务 runScript 并且脚本位于 /src/main/kotlin/script.kt(顶级包)中,那么任务定义如下:

task runScript(type: JavaExec) {
    main = 'ScriptKt'
    classpath = sourceSets.main.runtimeClasspath
}

您的 main 函数不属于 Testing class。所以 com.myProject.Testing 不是有效的主要 class 名称。

您应该将 main 方法移动到 Testing class 的 companion object(就像 class 的静态方法),或者更改 gradle 构建文件以使用生成的 class 名称作为顶级声明,遵循约定:

package_name + . + capitalized_file_name + Kt

如果您的文件名为 Testing.kt,并且您的声明包是 com.myProject,您的完全限定主 class 名称应该是:

com.myProject.TestingKt(注意最后的Kt

但是我在 Testing.kt 的顶部没有看到 package 声明。您是为了简洁而忽略了它还是真的忘记了它?