Strobe_
Strobe_

Reputation: 515

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

I have Ktor project that has a main called Application.kt.

The layout is like so

.
└── 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

But now I have a script that I would like to run as part of Kubernetes init container, the file looks like this

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()
}

i've tried running ./gradlew testing which I have defined in my build.gradle like so:

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

but to no avail, does anybody have any ideas?

When trying to run using the above gradle command i get the error Could not find or load main class Testing

my 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' }
}

Upvotes: 0

Views: 2144

Answers (2)

Joffrey
Joffrey

Reputation: 37809

Your main function is not part of the Testing class. So com.myProject.Testing is not a valid main class name.

You should either move your main method to the companion object of the Testing class (like a static method of the class), or change the gradle build file to use the generated class name for top-level declarations, which follows the convention:

package_name + . + capitalized_file_name + Kt

If your file is named Testing.kt, and the package of your declarations is com.myProject, your fully qualified main class name should be:

com.myProject.TestingKt (note the Kt at the end)

But I don't see a package declaration at the top of Testing.kt. Did you just omit it for brevity or did you actually forget it?

Upvotes: 2

Aleksei Tirman
Aleksei Tirman

Reputation: 7119

You can use the following format to define a task:

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

where <task-name> — the name for a Gradle task, <package> — package where your script class resides, <file-class> — uppercased filename without extension + Kt suffix.

For example, if I call a task runScript and the script is located in /src/main/kotlin/script.kt (top level package) then the task definition will be the following:

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

Upvotes: 2

Related Questions