diff --git a/.github/workflows/check-kdocs.yml b/.github/workflows/check-kdocs.yml index 549bead0e..b6f052eac 100644 --- a/.github/workflows/check-kdocs.yml +++ b/.github/workflows/check-kdocs.yml @@ -4,43 +4,46 @@ on: pull_request: branches: - 3.X - paths: - - 'pom.xml' - - 'src/main/**.java' - - 'src/test/**.java' - - 'src/main/**.kt' - - 'src/test/**.kt' push: branches: - 3.X - paths: - - 'pom.xml' - - 'src/main/**.java' - - 'src/test/**.java' - - 'src/main/**.kt' - - 'src/test/**.kt' + jobs: check-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + + - name: Set up JDK 24 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' - cache: 'maven' - - name: Compile and run tests with Maven - run: mvn -B --file pom.xml -Dkotlin.compiler.incremental=false test + # Toolchain is 24 due to certain modules, but we compile down to 17 for most modules + java-version: '24' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + + - name: Run tests + run: ./gradlew test check-kdocs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + + - name: Set up JDK 24 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' - cache: 'maven' - - name: Build KDocs with Maven - run: mvn -P docs -B generate-sources dokka:dokka + # Toolchain is 24 due to certain modules, but we compile down to 17 for most modules + java-version: '24' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + + - name: Build KDocs + run: ./gradlew dokkaGenerate diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 81a5aa49b..3c330c5f1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,10 +3,6 @@ name: Deploy KDocs to Pages on: push: branches: ["3.X"] - paths: - - 'pom.xml' - - 'src/main/**.java' - - 'src/main/**.kt' workflow_dispatch: # Allow one concurrent deployment @@ -21,20 +17,27 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + + - name: Set up JDK 24 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' - cache: 'maven' - - name: Set release version - run: mvn -B BotCommandsBuild:set-ci-version + # Toolchain is 24 due to certain modules, but we compile down to 17 for most modules + java-version: '24' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + - name: Generate KDocs - run: mvn -B -P docs generate-sources dokka:dokka + run: ./gradlew dokkaGenerate + - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - path: ./target/dokka + path: ./build/dokka + publish-docs: name: Publish docs runs-on: ubuntu-latest diff --git a/.github/workflows/jitpack-preview.yml b/.github/workflows/jitpack-preview.yml index 115c0bce0..011e2e0f0 100644 --- a/.github/workflows/jitpack-preview.yml +++ b/.github/workflows/jitpack-preview.yml @@ -6,12 +6,6 @@ on: - reopened - synchronize - closed - paths: - - 'pom.xml' - - 'src/main/**.java' - - 'src/test/**.java' - - 'src/main/**.kt' - - 'src/test/**.kt' permissions: pull-requests: write diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index bed20aaa5..93ccbc7f8 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -1,5 +1,3 @@ -# https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-Apache-Maven - name: Publish to Maven Central on: release: @@ -11,30 +9,28 @@ jobs: if: github.event.release.draft == false steps: - uses: actions/checkout@v4 + - name: Configure Git User run: | git config user.email "41875020+freya022@users.noreply.github.com" git config user.name "freya022" - - name: Set up JDK 17 + + - name: Set up JDK 24 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' - cache: 'maven' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - gpg-private-key: ${{ secrets.OSSRH_GPG_SECRET_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - name: Set release version - run: mvn -B --file pom.xml BotCommandsBuild:set-ci-version + # Toolchain is 24 due to certain modules, but we compile down to 17 for most modules + java-version: '24' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + - name: Compile and release - run: > - mvn -B --file pom.xml - -P docs,release - -Dkotlin.compiler.incremental=false - deploy + run: ./gradlew publishToMavenCentral env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_TOKEN }} + ORG_GRADLE_PROJECT_mavenGpgSecretKey: ${{ secrets.GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_mavenGpgKeyId: ${{ secrets.GPG_KEY_ID }} diff --git a/.gitignore b/.gitignore index 74f4b87dd..23c4ccac9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,9 @@ *.iml .idea -target -release.properties -pom.xml.releaseBackup +build +.gradle +.kotlin -schemas/Test.json -/schemas dev-config dev-data \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index cb28b0e37..000000000 Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index eacdc9ed1..000000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/BotCommands-spring/build.gradle.kts b/BotCommands-spring/build.gradle.kts new file mode 100644 index 000000000..9b9c8e582 --- /dev/null +++ b/BotCommands-spring/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id("BotCommands-conventions") + id("BotCommands-publish-conventions") + alias(libs.plugins.ksp) +} + +dependencies { + api(projects.botCommands) + + // Logging + implementation(libs.kotlin.logging.jvm) + + // -------------------- SPRING DEPENDENCIES -------------------- + + // Spring Boot + api(libs.spring.boot) + api(libs.spring.boot.autoconfigure) + + // -------------------- ANNOTATION PROCESSORS -------------------- + + ksp(projects.springPropertiesProcessor) + + // -------------------- TEST DEPENDENCIES -------------------- + + // Take the same test dependencies as the main library + testImplementation(rootProject.sourceSets.test.get().compileClasspath) + // Take the same test sources as the main library + testImplementation(rootProject.sourceSets.test.get().output) + + // Spring Boot + testImplementation(libs.spring.boot.starter) + testRuntimeOnly(libs.spring.boot.devtools) +} + +kotlin { + compilerOptions { + freeCompilerArgs.addAll( + "-Xjvm-default=all", + ) + } +} diff --git a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt similarity index 76% rename from src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt index 77805d70b..25bcf1f5b 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/ConfigConfigurers.kt @@ -1,7 +1,7 @@ package io.github.freya022.botcommands.api.core.config /** - * Base interface for runtime configuration, only usable with Spring, see sub-interfaces. + * Base interface for runtime configuration, see sub-interfaces. */ sealed interface BConfigurer { fun configure(builder: T) @@ -9,63 +9,45 @@ sealed interface BConfigurer { /** * Configurer for [BConfig]. - * - * Only usable with Spring. */ interface BConfigConfigurer : BConfigurer /** * Configurer for [BDatabaseConfig]. - * - * Only usable with Spring. */ interface BDatabaseConfigConfigurer : BConfigurer /** * Configurer for [BLocalizationConfig]. - * - * Only usable with Spring. */ interface BLocalizationConfigConfigurer : BConfigurer /** * Configurer for [BAppEmojisConfig]. - * - * Only usable with Spring. */ interface BAppEmojisConfigConfigurer : BConfigurer /** * Configurer for [BTextConfig]. - * - * Only usable with Spring. */ interface BTextConfigConfigurer : BConfigurer /** * Configurer for [BApplicationConfig]. - * - * Only usable with Spring. */ interface BApplicationConfigConfigurer : BConfigurer /** * Configurer for [BModalsConfig]. - * - * Only usable with Spring. */ interface BModalsConfigConfigurer : BConfigurer /** * Configurer for [BComponentsConfig]. - * - * Only usable with Spring. */ interface BComponentsConfigConfigurer : BConfigurer /** * Configurer for [BCoroutineScopesConfig]. - * - * Only usable with Spring. */ interface BCoroutineScopesConfigConfigurer : BConfigurer \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt similarity index 98% rename from src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt index 03e4d82b0..8e89206ca 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/api/core/config/JDAConfiguration.kt @@ -1,5 +1,3 @@ -@file:Suppress("ConfigurationProperties") - package io.github.freya022.botcommands.api.core.config import io.github.freya022.botcommands.api.core.JDAService @@ -10,9 +8,9 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.bind.Name import org.springframework.context.event.ContextClosedEvent +import java.time.Duration as JavaDuration import kotlin.time.Duration import kotlin.time.toKotlinDuration -import java.time.Duration as JavaDuration /** * Configuration properties for [JDAService]. diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsConfiguration.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsConfiguration.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsConfiguration.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsConfiguration.kt diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsInitializer.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsInitializer.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsInitializer.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringBotCommandsInitializer.kt diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDARestartListener.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDARestartListener.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDARestartListener.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDARestartListener.kt diff --git a/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDAServiceMismatchChecker.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDAServiceMismatchChecker.kt new file mode 100644 index 000000000..cd809f56a --- /dev/null +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/SpringJDAServiceMismatchChecker.kt @@ -0,0 +1,45 @@ +package io.github.freya022.botcommands.internal.core + +import io.github.freya022.botcommands.api.core.JDAService +import io.github.freya022.botcommands.api.core.annotations.BEventListener +import io.github.freya022.botcommands.api.core.config.JDAConfiguration +import io.github.freya022.botcommands.api.core.events.InjectedJDAEvent +import io.github.freya022.botcommands.internal.utils.reference +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.stereotype.Component + +private val logger = KotlinLogging.logger { } + +// Spring checks are slightly different, we want to tell the user to move them to their application environment, +// so the checks are consistent with condition annotations, as they can only check the environment +@Component +internal class SpringJDAServiceMismatchChecker { + @BEventListener + internal fun onJDA(event: InjectedJDAEvent, jdaConfiguration: JDAConfiguration, jdaService: JDAService) { + val environmentIntents = jdaConfiguration.intents + val jdaServiceIntents = jdaService.intents + if (environmentIntents != jdaServiceIntents) { + logger.warn { + """ + The intents given in JDAService and the environment should be the same! + Environment intents: ${environmentIntents.sorted()} + JDAService intents: ${jdaServiceIntents.sorted()} + Hint: you should get your intents from ${JDAConfiguration::intents.reference} + """.trimIndent() + } + } + + val environmentCacheFlags = jdaConfiguration.cacheFlags + val jdaServiceCacheFlags = jdaService.cacheFlags + if (environmentCacheFlags != jdaServiceCacheFlags) { + logger.warn { + """ + The cache flags given in JDAService and the environment should be the same! + Environment cache flags: ${environmentCacheFlags.sorted()} + JDAService cache flags: ${jdaServiceCacheFlags.sorted()} + Hint: you should get your caches flags from ${JDAConfiguration::cacheFlags.reference} + """.trimIndent() + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/annotations/InternalComponentScan.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/annotations/InternalComponentScan.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/annotations/InternalComponentScan.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/annotations/InternalComponentScan.kt diff --git a/src/main/kotlin/io/github/freya022/botcommands/autoconfigure/BotCommandsAutoConfiguration.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/autoconfigure/BotCommandsAutoConfiguration.kt similarity index 82% rename from src/main/kotlin/io/github/freya022/botcommands/autoconfigure/BotCommandsAutoConfiguration.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/autoconfigure/BotCommandsAutoConfiguration.kt index d22c2ea99..9f390a907 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/autoconfigure/BotCommandsAutoConfiguration.kt +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/autoconfigure/BotCommandsAutoConfiguration.kt @@ -1,4 +1,4 @@ -package io.github.freya022.botcommands.autoconfigure +package io.github.freya022.botcommands.internal.core.autoconfigure import io.github.freya022.botcommands.internal.core.SpringBotCommandsConfiguration import org.springframework.boot.autoconfigure.AutoConfiguration diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt similarity index 98% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt index 10c1ed607..a85e81ec7 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/BotCommandsConfigurations.kt @@ -5,16 +5,15 @@ import io.github.freya022.botcommands.api.core.config.* import io.github.freya022.botcommands.api.core.config.application.cache.ApplicationCommandsCacheConfig import io.github.freya022.botcommands.api.core.config.application.cache.ApplicationCommandsCacheConfigBuilder import io.github.freya022.botcommands.api.utils.EmojiUtils -import io.github.freya022.botcommands.internal.utils.throwArgument import net.dv8tion.jda.api.events.Event import net.dv8tion.jda.api.interactions.DiscordLocale import net.dv8tion.jda.api.requests.GatewayIntent import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.bind.Name +import java.time.Duration as JavaDuration import kotlin.io.path.Path import kotlin.time.Duration import kotlin.time.toKotlinDuration -import java.time.Duration as JavaDuration @ConfigurationProperties(prefix = "botcommands.core", ignoreUnknownFields = false) internal class BotCommandsCoreConfiguration( @@ -221,4 +220,4 @@ internal fun BComponentsConfigBuilder.applyConfig(configuration: BotCommandsComp enable = configuration.enable } -private fun unusable(): Nothing = throwArgument("Cannot be used") +private fun unusable(): Nothing = throw UnsupportedOperationException("Cannot be used") diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigProvider.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigProvider.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigProvider.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigProvider.kt diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt similarity index 85% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt index 00293ced4..805ff6771 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/DefaultSearchPathConfigurer.kt @@ -3,9 +3,7 @@ package io.github.freya022.botcommands.internal.core.config import io.github.freya022.botcommands.api.core.config.BConfigBuilder import io.github.freya022.botcommands.api.core.config.BConfigConfigurer import io.github.freya022.botcommands.internal.core.annotations.InternalComponentScan -import io.github.freya022.botcommands.internal.utils.annotationRef import org.springframework.beans.factory.getBeansWithAnnotation -import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.context.ApplicationContext import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.ComponentScans @@ -19,7 +17,7 @@ internal open class DefaultSearchPathConfigurer(private val applicationContext: val allUserPackages = (scans + groupScans).flatMap { it.packages } check(allUserPackages.isNotEmpty()) { - "You must configure at least one package on your ${annotationRef()} (recommended) or in a ${annotationRef()}" + "You must configure at least one package on your @SpringBootApplication (recommended) or in a @ComponentScan" } builder.packages += allUserPackages } diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringBotCommandsBootstrap.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringBotCommandsBootstrap.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringBotCommandsBootstrap.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringBotCommandsBootstrap.kt diff --git a/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringInstantiableServices.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringInstantiableServices.kt new file mode 100644 index 000000000..792c2a4e1 --- /dev/null +++ b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringInstantiableServices.kt @@ -0,0 +1,39 @@ +package io.github.freya022.botcommands.internal.core.service + +import io.github.freya022.botcommands.api.core.config.BConfig +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.context.ApplicationContext +import org.springframework.stereotype.Service +import kotlin.reflect.KClass + +private val logger = KotlinLogging.logger { } + +@Service +internal class SpringInstantiableServices internal constructor( + private val config: BConfig, + private val applicationContext: ApplicationContext +) : InstantiableServices { + override fun getAllPrimaryTypes(): Set> { + return applicationContext.beanDefinitionNames + .asSequence() + .map { beanName -> + val type = applicationContext.getType(beanName) + if (type != null) { + type + } else { + logger.debug { "Creating bean '$beanName' as no type is available" } + applicationContext.getBean(beanName).javaClass + } + } + .filter { type -> + if (config.packages.any { type.packageName.startsWith(it) }) + return@filter true + if (type.packageName.startsWith("io.github.freya022.botcommands")) + return@filter true + if (type in config.classes) + return@filter true + return@filter false + } + .mapTo(hashSetOf()) { it.kotlin } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringServiceContainer.kt b/BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringServiceContainer.kt similarity index 100% rename from src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringServiceContainer.kt rename to BotCommands-spring/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/SpringServiceContainer.kt diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/BotCommands-spring/src/main/resources/META-INF/additional-spring-configuration-metadata.json similarity index 100% rename from src/main/resources/META-INF/additional-spring-configuration-metadata.json rename to BotCommands-spring/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/src/main/resources/META-INF/spring.factories b/BotCommands-spring/src/main/resources/META-INF/spring.factories similarity index 100% rename from src/main/resources/META-INF/spring.factories rename to BotCommands-spring/src/main/resources/META-INF/spring.factories diff --git a/BotCommands-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/BotCommands-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..55e322c79 --- /dev/null +++ b/BotCommands-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +io.github.freya022.botcommands.internal.core.autoconfigure.BotCommandsAutoConfiguration \ No newline at end of file diff --git a/src/test/kotlin/io/github/freya022/botcommands/spring/test/SpringMain.kt b/BotCommands-spring/src/test/kotlin/io/github/freya022/botcommands/spring/test/SpringMain.kt similarity index 100% rename from src/test/kotlin/io/github/freya022/botcommands/spring/test/SpringMain.kt rename to BotCommands-spring/src/test/kotlin/io/github/freya022/botcommands/spring/test/SpringMain.kt diff --git a/src/test/resources/application.properties b/BotCommands-spring/src/test/resources/application.properties similarity index 100% rename from src/test/resources/application.properties rename to BotCommands-spring/src/test/resources/application.properties diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..2cc870ab2 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,166 @@ +plugins { + id("BotCommands-conventions") + id("BotCommands-publish-conventions") + alias(libs.plugins.ksp) +} + +configurations.all { + exclude(module = "opus-java") + exclude(module = "tink") +} + +dependencies { + // -------------------- CORE DEPENDENCIES -------------------- + + // Kotlin + api(libs.kotlin.reflect) + api(libs.kotlinx.coroutines.core) + compileOnly(libs.kotlinx.coroutines.debug) // Optional + + // Logging + api(libs.slf4j.api) + implementation(libs.kotlin.logging.jvm) + + // JDA + api(libs.jda) + api(libs.jda.ktx) + + // Classpath scanning + api(libs.classgraph) + + // -------------------- GLOBAL DEPENDENCIES -------------------- + + api(libs.kotlinx.datetime.jvm) + + // Deserialization + api(libs.jackson.databind) + api(libs.jackson.module.kotlin) + + // Efficient data structures + api(libs.trove4j.core) + + // Rate limiting + api(libs.bucket4j.jdk17.core) + + // -------------------- DATABASE DEPENDENCIES -------------------- + + // SQL connection pooling + compileOnly(libs.hikaricp) // Optional + + // -------------------- EMOJI DEPENDENCIES -------------------- + + // All Unicode emojis + api(libs.jemoji) + // JDA-specific emojis + api(libs.jda.emojis) + + // -------------------- AUTOCOMPLETE DEPENDENCIES -------------------- + + // Fuzzy matching + api(libs.java.string.similarity) + + // Caching + implementation(libs.caffeine) + + // -------------------- SPRING DEPENDENCIES -------------------- + + // Spring Boot (only for compatibility that cannot be put in a different module) + compileOnly(libs.spring.boot) // Optional + compileOnly(libs.spring.boot.autoconfigure) // Optional + + // -------------------- ANNOTATION DEPENDENCIES -------------------- + + api(libs.jsr305) + compileOnly(libs.jetbrains.annotations) + + // -------------------- ANNOTATION PROCESSORS -------------------- + + ksp(projects.springPropertiesProcessor) + + // -------------------- TEST DEPENDENCIES -------------------- + + // Mocking + testImplementation(libs.mockk.jvm) + + // Logging + testImplementation(libs.logback.classic) + + // Coroutines + testImplementation(libs.stacktrace.decoroutinator.jvm) + + // Database + testImplementation(libs.postgresql) + testImplementation(libs.h2) + testImplementation(libs.flyway.core) + testImplementation(libs.flyway.database.postgresql) + testImplementation(libs.hikaricp) + + // Persistent rate limiting + testImplementation(libs.bucket4j.jdk17.postgresql) + + // YAML (de)serialization + testImplementation(libs.jackson.dataformat.yaml) + + // Upgrade because kotlinx-coroutines-debug somehow has an ANCIENT version + testImplementation(libs.byte.buddy) + testImplementation(libs.byte.buddy.agent) + + // Test stuff + testImplementation(libs.kotlin.metadata.jvm) + + // The Spring Boot module will include them at runtime, + // but we need to make sure the main module works without it + testCompileOnly(libs.spring.boot) + testCompileOnly(libs.spring.boot.autoconfigure) + + dokka(rootProject) + dokka(projects.botCommandsSpring) +} + +val generateInfo by tasks.registering(GenerateBCInfoTask::class) { + doNotTrackState("Can't know when Git hash/branch changes") + outputs.upToDateWhen { false } +} + +ksp { + excludedSources.from(generateInfo) +} + +sourceSets { + main { + java { + srcDir(generateInfo) + exclude("**/\$BCInfo.java") + } + } +} + +// Register examples +sourceSets { + register("examples") { + compileClasspath += sourceSets.main.get().output + runtimeClasspath += sourceSets.main.get().output + } +} + +configurations["examplesApi"].extendsFrom(configurations["api"], configurations["testApi"]) +configurations["examplesImplementation"].extendsFrom(configurations["implementation"], configurations["testImplementation"]) +configurations["examplesCompileOnly"].extendsFrom(configurations["compileOnly"], configurations["testCompileOnly"]) + +dokka { + dokkaSourceSets.configureEach { + suppressedFiles.from("src/main/java/io/github/freya022/botcommands/api/\$BCInfo.java") + suppressGeneratedFiles = false + } +} + +kotlin { + compilerOptions { + freeCompilerArgs.addAll( + "-Xjvm-default=all", + "-Xcontext-receivers", + "-Xsuppress-warning=CONTEXT_RECEIVERS_DEPRECATED", + "-Xconsistent-data-class-copy-visibility", + ) + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..a8cc5d668 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,33 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() + gradlePluginPortal() +} + +dependencies { + implementation(libs.kotlin.plugin) + implementation(libs.maven.publish.plugin) + implementation(libs.dokka.plugin) +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +// Kotlin configuration for the precompiled classes +kotlin { + compilerOptions { + // Version of the buildscript bytecode, so Gradle shuts up + jvmTarget = JvmTarget.JVM_17 + + freeCompilerArgs.addAll( + "-Xjsr305=strict", + ) + } +} \ No newline at end of file diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 000000000..fa8bc7492 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/BotCommands-conventions.gradle.kts b/buildSrc/src/main/kotlin/BotCommands-conventions.gradle.kts new file mode 100644 index 000000000..ee12aa6d7 --- /dev/null +++ b/buildSrc/src/main/kotlin/BotCommands-conventions.gradle.kts @@ -0,0 +1,40 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") +} + +group = "io.github.freya022" + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(24) + } + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +tasks.withType { + options.compilerArgs.add("-parameters") +} + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + testImplementation(kotlin("test")) + testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.0") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_17 + + freeCompilerArgs.addAll( + "-Xjsr305=strict", + ) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/BotCommands-publish-conventions.gradle.kts b/buildSrc/src/main/kotlin/BotCommands-publish-conventions.gradle.kts new file mode 100644 index 000000000..425fe4d9b --- /dev/null +++ b/buildSrc/src/main/kotlin/BotCommands-publish-conventions.gradle.kts @@ -0,0 +1,128 @@ +import com.vanniktech.maven.publish.SonatypeHost + +plugins { + `java-library` + signing + id("com.vanniktech.maven.publish") + id("org.jetbrains.dokka") +} + +val mavenCentralUsername: String? by project +val mavenCentralPassword: String? by project +/** + * 1. Generate a key pair with `gpg --gen-key`, it will ask for a key name and an email address + * 2. Start editing the key with `gpg --edit-key `, you should see a `gpg>` prompt + * 3. (Optional) Modify the expiry of your primary key with `expire` + * 4. If a subkey (`ssb`) was generated automatically, you can delete it by selecting it with `key 1` and running `delkey` + * 5. Add a subkey with `addkey`, select `RSA (sign only)` + * 6. Save everything with `save`, it will exit the gpg prompt + * 7. Show the subkey IDs with `gpg -K --keyid-format short`, you should see two keys: + * - `sec ed25519/ [SC]`, with the line below being the public key + * - `ssb rsa/ [S]` + * 8. Set `mavenGpgKeyId` with the subkey id + * 9. Set `mavenGpgSecretKey` with the secret key using `gpg --export-secret-key --armor ` + */ +val mavenGpgKeyId: String? by project +val mavenGpgSecretKey: String? by project + +val canSign = mavenGpgKeyId != null && mavenGpgSecretKey != null +val canPublish = mavenCentralUsername != null && mavenCentralPassword != null && canSign + +version = Version( + major = "3", + minor = "0", + revision = "0", + classifier = "beta.2", + // isRelease = isCi || canPublish + isDev = !GitUtils.isCI(providers) && !canPublish +) + +val effectiveTag = if (canPublish) { + GitUtils.getHeadTag(logger, providers, projectDir.absolutePath) ?: error("Attempted to publish on a non-release commit") +} else { + "3.X" +} + +java { + withSourcesJar() +} + +dokka { + dokkaSourceSets.configureEach { + jdkVersion = 17 + + perPackageOption { + matchingRegex = ".*internal.*" + suppress = true + } + + sourceLink { + localDirectory = rootDir + remoteUrl("https://github.com/freya022/BotCommands/tree/${effectiveTag}") + remoteLineSuffix = "#L" + } + + externalDocumentationLinks.register("JDA") { + url("https://docs.jda.wiki") + packageListUrl("https://docs.jda.wiki/element-list") + } + + externalDocumentationLinks.register("JetBrainsAnnotations") { + url("https://javadoc.io/doc/org.jetbrains/annotations/26.0.2") + packageListUrl("https://javadoc.io/doc/org.jetbrains/annotations/26.0.2/package-list") + } + + externalDocumentationLinks.register("Spring") { + url("https://docs.spring.io/spring-framework/docs/current/javadoc-api") + packageListUrl("https://docs.spring.io/spring-framework/docs/current/javadoc-api/element-list") + } + + externalDocumentationLinks.register("Bucket4J") { + url("https://javadoc.io/doc/com.bucket4j/bucket4j_jdk17-core/8.14.0") + packageListUrl("https://javadoc.io/doc/com.bucket4j/bucket4j_jdk17-core/8.14.0/element-list") + } + } +} + +signing { + isRequired = canPublish + + useInMemoryPgpKeys(mavenGpgKeyId, mavenGpgSecretKey, "") +} + +mavenPublishing { + if (canPublish) { + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, automaticRelease = false) // TODO set to automatic when done testing + + signAllPublications() + } + + pom { + description = "A Kotlin-first (and Java) framework that makes creating Discord bots a piece of cake, using the JDA library." + url = "https://github.com/freya022/BotCommands" + inceptionYear = "2020" + + licenses { + license { + name = "Mozilla Public License 2.0" + url = "https://opensource.org/licenses/MPL-2.0" + distribution = "repo" + } + } + + developers { + developer { + name = "freya022" + email = "41875020+freya022@users.noreply.github.com" + url = "https://github.com/freya022" + } + } + + scm { + connection = "scm:git:https://github.com/freya022/BotCommands.git" + developerConnection = connection + url = "https://github.com/freya022/BotCommands" + tag = effectiveTag + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/GenerateBCInfoTask.kt b/buildSrc/src/main/kotlin/GenerateBCInfoTask.kt new file mode 100644 index 000000000..d1eec806c --- /dev/null +++ b/buildSrc/src/main/kotlin/GenerateBCInfoTask.kt @@ -0,0 +1,59 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.file.Directory +import org.gradle.api.provider.ProviderFactory +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault +import java.time.Instant +import javax.inject.Inject + +@DisableCachingByDefault +abstract class GenerateBCInfoTask : DefaultTask() { + + @get:InputFile + val inputFile = project.layout.projectDirectory.file("src/main/java/io/github/freya022/botcommands/api/\$BCInfo.java") + + @get:OutputDirectory + val outputDir = project.layout.buildDirectory.dir("generated/sources/BotCommands/main/java") + + @get:Input + val projectDir = project.projectDir.absolutePath + + @get:Inject + abstract val providers: ProviderFactory + + @get:Input + val version: Version = project.version as Version + + @get:Input + val jdaVersion = project.configurations.getByName("compileClasspath") + .incoming.dependencies.find { it.name.endsWith("JDA") }!!.version!! + + @TaskAction + fun run() { + val attributes = mapOf( + "version-major" to version.major, + "version-minor" to version.minor, + "version-revision" to version.revision, + "version-classifier" to (version.classifier ?: "null"), + "branch-name" to (GitUtils.getCommitBranch(logger, providers, projectDir) ?: "null"), + "commit-hash" to (GitUtils.getCommitHash(logger, providers, projectDir) ?: "null"), + "build-jda-version" to jdaVersion, + "build-time" to Instant.now().toEpochMilli().toString(), + ) + + val initialContent = inputFile.asFile.readText() + val filteredContent = initialContent.replaceTokens(attributes).replace("\$BCInfo", "BCInfo") + + val bcInfoFile = outputDir.get().file("io/github/freya022/botcommands/api/BCInfo.java").asFile + bcInfoFile.parentFile.mkdirs() + bcInfoFile.writeText(filteredContent) + } + + private fun String.replaceTokens(map: Map): String { + return map.entries.fold(this) { current, (key, value) -> current.replace("@$key@", value) } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/GitUtils.kt b/buildSrc/src/main/kotlin/GitUtils.kt new file mode 100644 index 000000000..744f8b6d5 --- /dev/null +++ b/buildSrc/src/main/kotlin/GitUtils.kt @@ -0,0 +1,75 @@ +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.file.Directory +import org.gradle.api.logging.Logger +import org.gradle.api.provider.ProviderFactory +import java.io.IOException + +object GitUtils { + + fun isCI(providers: ProviderFactory): Boolean { + return (providers.systemProperty("BUILD_NUMBER").isPresent // Jenkins + || providers.environmentVariable("BUILD_NUMBER").isPresent + || providers.systemProperty("GIT_COMMIT").isPresent // Jitpack + || providers.environmentVariable("GIT_COMMIT").isPresent + || providers.systemProperty("GITHUB_ACTIONS").isPresent // GitHub Actions + || providers.environmentVariable("GITHUB_ACTIONS").isPresent) + } + + fun getCommitBranch(logger: Logger, providers: ProviderFactory, directory: String): String? { + try { + //Jitpack builds are detached from a branch, this will return the HEAD hash, + // which can still be used on GitHub to get the state of the repository at that point + val jitpackBranch = providers.environmentVariable("GIT_BRANCH").getOrNull() + if (jitpackBranch != null) return jitpackBranch + + val output = providers.exec { + commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") + workingDir(directory) + } + + output.result.get().assertNormalExitValue() + + return output.standardOutput.asText.get().lineSequence().first() + } catch (e: Exception) { + logger.error("Unable to get commit branch", e) + return null + } + } + + fun getCommitHash(logger: Logger, providers: ProviderFactory, directory: String): String? { + try { + val jitpackCommit = providers.environmentVariable("GIT_COMMIT").getOrNull() + if (jitpackCommit != null) return jitpackCommit + + val output = providers.exec { + commandLine("git", "rev-parse", "--verify", "HEAD") + workingDir(directory) + } + + output.result.get().assertNormalExitValue() + + return output.standardOutput.asText.get().lineSequence().first() + } catch (e: Exception) { + logger.error("Unable to get commit hash", e) + return null + } + } + + fun getHeadTag(logger: Logger, providers: ProviderFactory, directory: String): String? { + try { + val output = providers.exec { + commandLine("git", "describe", "--tags", "--abbrev=0", "--exact-match") + workingDir(directory) + isIgnoreExitValue = true + } + + if (output.result.get().exitValue == 128) { return null } + + return output.standardOutput.asText.get().lineSequence().first() + } catch (e: Exception) { + logger.error("Unable to get head tag", e) + return null + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Version.kt b/buildSrc/src/main/kotlin/Version.kt new file mode 100644 index 000000000..0d8aaebd3 --- /dev/null +++ b/buildSrc/src/main/kotlin/Version.kt @@ -0,0 +1,39 @@ +import java.io.ObjectInputStream +import java.io.ObjectOutputStream +import java.io.Serializable + +data class Version( + val major: String, + val minor: String, + val revision: String, + val classifier: String?, + val isDev: Boolean, +) : Serializable { + + override fun toString(): String { + return "$major.$minor.$revision-$classifier" + let { if (isDev) "_DEV" else "" } + } + + private fun writeObject(out: ObjectOutputStream) { + out.defaultWriteObject() + } + + private fun readObject(out: ObjectInputStream) { + out.defaultReadObject() + } + + companion object { + private val versionPattern = Regex("""(\d+)\.(\d+)\.(\d+)(?:-(\w+\.\d+))?(?:_DEV)?""") + + fun parseOrNull(version: String): Version? { + val groups = versionPattern.matchEntire(version)?.groups ?: return null + + val major = groups[1]?.value ?: return null + val minor = groups[2]?.value ?: return null + val revision = groups[3]?.value ?: return null + val classifier = groups[4]?.value + + return Version(major, minor, revision, classifier, version.endsWith("_DEV")) + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..a2c29543e --- /dev/null +++ b/gradle.properties @@ -0,0 +1,9 @@ +# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties + +org.gradle.configuration-cache=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2G +kotlin.daemon.jvmargs=-Xmx2G +org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled +org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..04ea8a2c1 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,126 @@ +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +# Plugins +maven-publish-plugin = "0.32.0" +dokka-plugin = "2.0.0" + +# Libraries +kotlin = "2.1.0" +kotlinx-coroutines = "1.10.1" + +stacktrace-decoroutinator-jvm = "2.4.8" + +slf4j-api = "2.0.16" +logback-classic = "1.5.16" +kotlin-logging-jvm = "7.0.3" + +jda = "5.5.0" +jda-ktx = "0.12.0" + +classgraph = "4.8.179" + +kotlinx-datetime-jvm = "0.6.1" + +jackson = "2.18.3" + +kotlinx-serialization = "1.8.1" + +trove4j-core = "3.1.0" + +jda-emojis = "3.0.0" +jemoji = "1.6.0" + +caffeine = "3.2.0" + +java-string-similarity = "2.0.0" + +jsr305 = "3.0.2" +jetbrains-annotations = "26.0.2" + +spring-boot = "3.4.2" + +h2 = "2.3.232" +postgresql = "42.7.5" # Tied to [[ComponentRepository#checkPostgresVersion]] +hikaricp = "6.2.1" +flyway = "11.2.0" + +bucket4j-jdk17-core = "8.14.0" +bucket4j-jdk17-postgresql = "8.14.0" + +mockk-jvm = "1.13.16" + +byte-buddy = "1.16.1" +byte-buddy-agent = "1.16.1" + +ksp = "2.1.21-2.0.2" + +jetbrains-markdown = "0.7.3" + +[plugins] +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } + +[libraries] +kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +maven-publish-plugin = { module = "com.vanniktech.maven.publish:com.vanniktech.maven.publish.gradle.plugin", version.ref = "maven-publish-plugin" } +dokka-plugin = { module = "org.jetbrains.dokka:org.jetbrains.dokka.gradle.plugin", version.ref = "dokka-plugin" } + +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } +kotlin-metadata-jvm = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlin" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-debug = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-debug", version.ref = "kotlinx-coroutines" } + +stacktrace-decoroutinator-jvm = { module = "dev.reformator.stacktracedecoroutinator:stacktrace-decoroutinator-jvm", version.ref = "stacktrace-decoroutinator-jvm" } + +slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j-api" } +logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback-classic" } +kotlin-logging-jvm = { module = "io.github.oshai:kotlin-logging-jvm", version.ref = "kotlin-logging-jvm" } + +jda = { module = "net.dv8tion:JDA", version.ref = "jda" } +jda-ktx = { module = "club.minnced:jda-ktx", version.ref = "jda-ktx" } + +classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } + +kotlinx-datetime-jvm = { module = "org.jetbrains.kotlinx:kotlinx-datetime-jvm", version.ref = "kotlinx-datetime-jvm" } + +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } +jackson-dataformat-yaml = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", version.ref = "jackson" } +jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } + +kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } + +trove4j-core = { module = "net.sf.trove4j:core", version.ref = "trove4j-core" } + +jda-emojis = { module = "dev.freya02:jda-emojis", version.ref = "jda-emojis" } +jemoji = { module = "net.fellbaum:jemoji", version.ref = "jemoji" } + +caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" } + +java-string-similarity = { module = "info.debatty:java-string-similarity", version.ref = "java-string-similarity" } + +jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" } +jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" } + +spring-boot = { module = "org.springframework.boot:spring-boot", version.ref = "spring-boot" } +spring-boot-autoconfigure = { module = "org.springframework.boot:spring-boot-autoconfigure", version.ref = "spring-boot" } +spring-boot-devtools = { module = "org.springframework.boot:spring-boot-devtools", version.ref = "spring-boot" } +spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "spring-boot" } + +h2 = { module = "com.h2database:h2", version.ref = "h2" } +postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql" } +hikaricp = { module = "com.zaxxer:HikariCP", version.ref = "hikaricp" } +flyway-core = { module = "org.flywaydb:flyway-core", version.ref = "flyway" } +flyway-database-postgresql = { module = "org.flywaydb:flyway-database-postgresql", version.ref = "flyway" } + +bucket4j-jdk17-core = { module = "com.bucket4j:bucket4j_jdk17-core", version.ref = "bucket4j-jdk17-core" } +bucket4j-jdk17-postgresql = { module = "com.bucket4j:bucket4j_jdk17-postgresql", version.ref = "bucket4j-jdk17-postgresql" } + +mockk-jvm = { module = "io.mockk:mockk-jvm", version.ref = "mockk-jvm" } + +byte-buddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" } +byte-buddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "byte-buddy-agent" } + +ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } + +jetbrains-markdown = { module = "org.jetbrains:markdown", version.ref = "jetbrains-markdown" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..1b33c55ba Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ff23a68d7 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 000000000..23d15a936 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..db3a6ac20 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/mvnw b/mvnw deleted file mode 100644 index 8d937f4c1..000000000 --- a/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd deleted file mode 100644 index c4586b564..000000000 --- a/mvnw.cmd +++ /dev/null @@ -1,205 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml deleted file mode 100644 index f96d6f52f..000000000 --- a/pom.xml +++ /dev/null @@ -1,629 +0,0 @@ - - - 4.0.0 - - io.github.freya022 - BotCommands - - - - - 3.0.0-beta.2_DEV - BotCommands - - A Kotlin-first (and Java) framework that makes creating Discord bots a piece of cake, using the JDA library. - - https://github.com/freya022/BotCommands - - - - freya022 - 41875020+freya022@users.noreply.github.com - - - - - UTF-8 - - 2.1.0 - 1.10.1 - 3.4.2 - 11.2.0 - 8.14.0 - 2.18.3 - - 2.0 - 2.0 - 17 - true - - - - - Mozilla Public License 2.0 - https://opensource.org/licenses/MPL-2.0 - repo - - - - - scm:git:https://github.com/freya022/BotCommands.git - scm:git:https://github.com/freya022/BotCommands.git - https://github.com/freya022/BotCommands - 3.X - - - - - docs - - - - org.jetbrains.dokka - dokka-maven-plugin - 1.9.20 - - - package - - dokka - - - - - 17 - true - - - src - ${project.scm.url}/tree/${project.scm.tag}/src - #L - - - ${project.basedir}/src/main/java/io/github/freya022/botcommands/api/$BCInfo.java - - ${project.basedir}/src/main/java - ${project.build.directory}/generated-sources - ${project.basedir}/src/main/kotlin - - - - https://docs.jda.wiki/ - https://docs.jda.wiki/element-list - - - https://javadoc.io/doc/org.jetbrains/annotations/23.0.0 - https://javadoc.io/doc/org.jetbrains/annotations/23.0.0/element-list - - - https://docs.spring.io/spring-framework/docs/current/javadoc-api - https://docs.spring.io/spring-framework/docs/current/javadoc-api/element-list - - - https://javadoc.io/doc/com.bucket4j/bucket4j_jdk17-core/${bucket4j.version} - https://javadoc.io/doc/com.bucket4j/bucket4j_jdk17-core/${bucket4j.version}/element-list - - - - - .*internal.* - true - - - - - - - - - release - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.4.1 - - - enforce-all-profiles-are-activated - - enforce - - - - - docs - - - true - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - freya02 - - - - - - dokka-jar - package - - jar - - - javadoc - ${project.build.directory}/dokka - false - - - - - - org.sonatype.central - central-publishing-maven-plugin - 0.7.0 - true - - central - true - - - - org.apache.maven.plugins - maven-gpg-plugin - 3.2.4 - - - sign-artifacts - verify - - sign - - - - - - - org.apache.maven.plugins - maven-install-plugin - 3.1.1 - - - - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.4.1 - - - enforce-maven - - enforce - - - - - 3.6.3 - - - true - - - - - - io.github.freya022 - BotCommandsBuild-maven-plugin - 01a97655cd - - - - generate-version-info - generate-configuration-metadata - check-ci-version - - - - - - ${project.basedir}/src/main/kotlin - - - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - -Xjvm-default=all - -Xcontext-receivers - -Xsuppress-warning=CONTEXT_RECEIVERS_DEPRECATED - -Xconsistent-data-class-copy-visibility - - - - - compile - - compile - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/main/java - - ${project.build.directory}/generated-sources - - - - - test-compile - - test-compile - - - - ${project.basedir}/src/test/kotlin - ${project.basedir}/src/test/java - - ${project.basedir}/src/examples/kotlin - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.12.1 - - 17 - - -parameters - - - io/github/freya022/botcommands/api/$BCInfo.java - - - - - - default-compile - none - - - - default-testCompile - none - - - java-compile - compile - - compile - - - - java-test-compile - test-compile - - testCompile - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 3.5.0 - - - generate-sources - - add-source - - - - src/main/kotlin - - ${project.build.directory}/generated-sources - - - - - examples-test-sources - generate-test-sources - - add-test-source - - - - src/examples/kotlin - - - - - examples-test-resources - generate-test-resources - - add-test-resource - - - - - src/examples/resources - - - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.0 - - - attach-sources - - jar-no-fork - - - io/github/freya022/botcommands/api/$BCInfo.java - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - - org.codehaus.mojo - versions-maven-plugin - 2.16.2 - - file:///${project.basedir}/rules.xml - - - - - - - - jitpack - https://jitpack.io - - - - - - org.springframework.boot - spring-boot-starter - ${spring-boot.version} - true - - - - org.jetbrains.kotlin - kotlin-stdlib - ${kotlin.version} - - - org.jetbrains.kotlin - kotlin-reflect - ${kotlin.version} - - - org.jetbrains.kotlinx - kotlinx-coroutines-core - ${kotlin.coroutine.version} - - - org.jetbrains.kotlinx - kotlinx-coroutines-debug - ${kotlin.coroutine.version} - true - - - org.jetbrains.kotlinx - kotlinx-datetime-jvm - 0.6.1 - - - net.dv8tion - JDA - 5.5.0 - - - club.minnced - opus-java - - - com.google.crypto.tink - tink - - - provided - - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.module - jackson-module-kotlin - ${jackson.version} - - - club.minnced - jda-ktx - 0.12.0 - - - com.google.code.findbugs - jsr305 - 3.0.2 - - - net.fellbaum - jemoji - 1.6.0 - - - dev.freya02 - jda-emojis - 3.0.0 - - - org.jetbrains - annotations - 26.0.2 - provided - - - io.github.classgraph - classgraph - 4.8.179 - - - net.sf.trove4j - core - 3.1.0 - - - com.github.ben-manes.caffeine - caffeine - 3.2.0 - - - info.debatty - java-string-similarity - 2.0.0 - - - org.slf4j - slf4j-api - 2.0.16 - - - io.github.oshai - kotlin-logging-jvm - 7.0.3 - - - com.bucket4j - bucket4j_jdk17-core - ${bucket4j.version} - - - com.bucket4j - bucket4j_jdk17-postgresql - ${bucket4j.version} - test - - - dev.reformator.stacktracedecoroutinator - stacktrace-decoroutinator-jvm - 2.4.8 - test - - - org.springframework.boot - spring-boot-devtools - ${spring-boot.version} - test - - - ch.qos.logback - logback-classic - 1.5.16 - test - - - org.postgresql - postgresql - 42.7.5 - test - - - com.h2database - h2 - 2.3.232 - test - - - org.flywaydb - flyway-core - ${flyway.version} - test - - - org.flywaydb - flyway-database-postgresql - ${flyway.version} - test - - - com.zaxxer - HikariCP - 6.2.1 - true - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - ${jackson.version} - test - - - org.junit.jupiter - junit-jupiter - 5.11.4 - test - - - io.mockk - mockk-jvm - 1.13.16 - test - - - net.bytebuddy - byte-buddy - 1.16.1 - test - - - net.bytebuddy - byte-buddy-agent - 1.16.1 - test - - - org.jetbrains.kotlin - kotlin-metadata-jvm - ${kotlin.version} - test - - - diff --git a/rules.xml b/rules.xml deleted file mode 100644 index b2622f428..000000000 --- a/rules.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - .+-(?:Beta|RC).* - - - - - .+-(?:RC|Beta).* - - - - - .+-alpha.+ - - - - - .+-rc.+ - - - - - .+_DEV - - - - - .+-M\d+ - - - - \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..b13e33fb7 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,6 @@ +rootProject.name = "BotCommands" + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + +include(":spring-properties-processor") +include(":BotCommands-spring") diff --git a/spring-properties-processor/build.gradle.kts b/spring-properties-processor/build.gradle.kts new file mode 100644 index 000000000..793619728 --- /dev/null +++ b/spring-properties-processor/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("BotCommands-conventions") + alias(libs.plugins.kotlinx.serialization) +} + +dependencies { + implementation(libs.ksp) + implementation(libs.kotlinx.serialization) + implementation(libs.jetbrains.markdown) +} + +kotlin { + compilerOptions { + freeCompilerArgs.addAll( + "-Xcontext-receivers", + "-Xsuppress-warning=CONTEXT_RECEIVERS_DEPRECATED", + ) + } +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringMetadata.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringMetadata.kt new file mode 100644 index 000000000..d79a4d15c --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringMetadata.kt @@ -0,0 +1,50 @@ +package io.github.freya022.botcommands.properties.processor + +import kotlinx.serialization.Serializable + +@Serializable +class SpringMetadata( + val groups: MutableList, + val properties: MutableList, + val hints: MutableList, +) { + constructor() : this(arrayListOf(), arrayListOf(), arrayListOf()) +} + +@Serializable +class GroupMetadata( + val name: String, + val type: String, + val sourceType: String, +) + +@Serializable +class PropertyMetadata( + val name: String, + val defaultValue: String?, + val type: String, + val sourceType: String, + val description: String?, + val deprecation: Deprecation? +) { + + @Serializable + class Deprecation( + val reason: String, + val level: String, + val replacement: String?, + ) +} + +@Serializable +class ClassReferenceHint(val name: String, val providers: List) { + + @Serializable + class Provider(val name: String, val parameters: Parameters) { + + @Serializable + class Parameters(val target: String) + } + + constructor(name: String, targetClass: String) : this(name, listOf(Provider("class-reference", Provider.Parameters(targetClass)))) +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessor.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessor.kt new file mode 100644 index 000000000..cf92ad3cf --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessor.kt @@ -0,0 +1,170 @@ +package io.github.freya022.botcommands.properties.processor + +import com.google.devtools.ksp.containingFile +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.* +import io.github.freya022.botcommands.properties.processor.utils.* +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToStream +import org.intellij.markdown.ast.getTextInNode +import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor +import org.intellij.markdown.parser.MarkdownParser + +private val configurationValueName = AnnotationName("io.github.freya022.botcommands.internal.core.config", "ConfigurationValue") +private val deprecatedValueName = AnnotationName("io.github.freya022.botcommands.internal.core.config", "DeprecatedValue") +private val ignoreDefaultValueName = AnnotationName("io.github.freya022.botcommands.internal.core.config", "IgnoreDefaultValue") + +val json = Json { + prettyPrint = true + explicitNulls = false + encodeDefaults = true +} + +private val classPattern = Regex("java.lang.Class<(.+)>") +private val collectionPattern = Regex("java\\.util\\.(?:Set|List)<(.+)>$") +private val mapPattern = Regex("java\\.util\\.Map<(.+), (.+)>$") + +class SpringPropertiesProcessor( + private val log: KSPLogger, + private val codeGenerator: CodeGenerator, +) : SymbolProcessor { + + private val metadata = SpringMetadata() + + private val processedNodes: MutableList = arrayListOf() + + override fun process(resolver: Resolver): List { + processedNodes += resolver.getSymbolsWithAnnotation(configurationValueName.name, inDepth = false) + .filterIsInstance() + .onEach(::processPropertyDeclaration) + + return emptyList() + } + + @OptIn(ExperimentalSerializationApi::class) + override fun finish() { + log.info("Processed ${processedNodes.size} nodes") + + codeGenerator.createNewFile( + dependencies = Dependencies( + aggregating = true, + sources = processedNodes.mapNotNull { it.containingFile }.toTypedArray() + ), + packageName = "META-INF", + fileName = "spring-configuration-metadata", + extensionName = "json" + ).use { + json.encodeToStream(metadata, it) + } + } + + private fun processPropertyDeclaration(propertyDeclaration: KSPropertyDeclaration) { + val configurationPropertiesAnnotation = propertyDeclaration.findAnnotation(configurationValueName) + val path: String = configurationPropertiesAnnotation.getOrDefault("path") + val defaultValue: String? = configurationPropertiesAnnotation.getIfSet("defaultValue") + + fun KSTypeReference.resolveTypedQualifiedName(from: KSDeclaration): String { + val type = resolve() + val qualifiedName = type.declaration.qualifiedName?.asString()?.toJavaType() + ?: throw IllegalArgumentException("Unknown type for $this in ${from.qualifiedName?.asString()}") + + return when { + type.arguments.isNotEmpty() -> { + val argumentsStr = type.arguments.joinToString { + when (it.variance) { + Variance.STAR -> "?" + else -> it.type!!.resolveTypedQualifiedName(from) + } + } + "$qualifiedName<$argumentsStr>" + } + else -> qualifiedName + } + } + // Get the type string if explicitly set, otherwise resolve + val typeStr = run { + val typeStr = configurationPropertiesAnnotation.getIfSet("type") + ?: propertyDeclaration.type.resolveTypedQualifiedName(propertyDeclaration) + // Wildcard is invalid for spring metadata, we ignore wildcards for the reference hint too + typeStr.replace("", "") + } + + val description = propertyDeclaration.docString?.let { docString -> + if (docString.contains("Default: ") && defaultValue == null && !propertyDeclaration.isAnnotationPresent(ignoreDefaultValueName)) { + log.warn("Missing default value for ${propertyDeclaration.qualifiedName?.asString()}") + } + + val parsedTree = MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(docString) + parsedTree.children + .asSequence() + .map { it.getTextInNode(docString) } + .filter { it.isNotBlank() } + .map { it.trim() } + .filterNot { it.startsWith("Spring property:") } + .filterNot { it.startsWith("@") } + .joinToString(" ") + .replace("\n", " ") // New lines in paragraph = structural wrapping + .tryAppendDot() + } + + tryPutClassReferenceHint(path, typeStr) + + val deprecation = propertyDeclaration.findAnnotationOrNull(deprecatedValueName)?.let { deprecatedValueAnnotation -> + val reason = deprecatedValueAnnotation.getOrDefault("reason").tryAppendDot() + val level = deprecatedValueAnnotation.getOrDefault("level").simpleName.asString().lowercase() + val replacement = deprecatedValueAnnotation.getIfSet("replacement") + PropertyMetadata.Deprecation(reason, level, replacement) + } + + metadata.properties += PropertyMetadata( + name = path, + defaultValue = defaultValue, + type = typeStr.toJavaType(), + sourceType = propertyDeclaration.canonicalName, + description = description, + deprecation = deprecation + ) + } + + private fun tryPutClassReferenceHint(name: String, typeStr: String) { + classPattern.matchEntire(typeStr)?.let { matchResult -> + val classTypeStr = matchResult.groupValues[1] + metadata.hints += ClassReferenceHint(name, classTypeStr) + return + } + + collectionPattern.matchEntire(typeStr)?.let { matchResult -> + val elementTypeStr = matchResult.groupValues[1] + // May or may not be a class + tryPutClassReferenceHint(name, elementTypeStr) + return + } + + mapPattern.matchEntire(typeStr)?.let { matchResult -> + val keyTypeStr = matchResult.groupValues[1] + val valueTypeStr = matchResult.groupValues[2] + // May or may not be a class + tryPutClassReferenceHint("$name.keys", keyTypeStr) + tryPutClassReferenceHint("$name.values", valueTypeStr) + return + } + } + + private fun String.toJavaType() = when (this) { + "kotlin.collections.List" -> "java.util.List" + "kotlin.collections.Set" -> "java.util.Set" + "kotlin.collections.Collection" -> "java.util.Collection" + "kotlin.collections.Map" -> "java.util.Map" + "kotlin.Boolean" -> "java.lang.Boolean" + "kotlin.Int" -> "java.lang.Integer" + "kotlin.Long" -> "java.lang.Long" + "kotlin.Double" -> "java.lang.Double" + "kotlin.String" -> "java.lang.String" + else -> { + if (this.startsWith("kotlin.")) + log.warn("Unmapped type: $this") + this + } + } +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessorProvider.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessorProvider.kt new file mode 100644 index 000000000..404a18b23 --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/SpringPropertiesProcessorProvider.kt @@ -0,0 +1,12 @@ +package io.github.freya022.botcommands.properties.processor + +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +class SpringPropertiesProcessorProvider : SymbolProcessorProvider { + + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + return SpringPropertiesProcessor(environment.logger, environment.codeGenerator) + } +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/AnnotationName.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/AnnotationName.kt new file mode 100644 index 000000000..93f908e7e --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/AnnotationName.kt @@ -0,0 +1,15 @@ +package io.github.freya022.botcommands.properties.processor.utils + +import com.google.devtools.ksp.symbol.KSAnnotation + +class AnnotationName( + val packageName: String, + val simpleName: String +) { + val name: String + get() = "$packageName.$simpleName" +} + +fun KSAnnotation.isA(annotationName: AnnotationName): Boolean = + shortName.asString() == annotationName.simpleName && + annotationType.resolve().declaration.qualifiedName!!.asString() == annotationName.name \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/KSP.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/KSP.kt new file mode 100644 index 000000000..d2ad8ba39 --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/KSP.kt @@ -0,0 +1,43 @@ +package io.github.freya022.botcommands.properties.processor.utils + +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSDeclaration +import com.google.devtools.ksp.symbol.KSValueArgument + +val KSDeclaration.canonicalName: String + get() { + tailrec fun String.prependDeclaringClass(declaration: KSDeclaration): String { + val parent = declaration.parentDeclaration ?: return this + return (parent.simpleName.asString() + "$" + this).prependDeclaringClass(parent) + } + + val parent = parentDeclaration ?: return "" + return parent.packageName.asString() + "." + parent.simpleName.asString().prependDeclaringClass(parent) + } + +fun KSAnnotation.getIfSet(name: String): R? { + return arguments.get(name).takeIf { defaultArguments.get(name) != it } +} + +fun KSAnnotation.getOrDefault(name: String): R { + return arguments[name] +} + +context(KSAnnotation) +@Suppress("UNCHECKED_CAST") +private operator fun Iterable.get(name: String): R = + singleOrNull { it.name?.asString() == name }?.value as R? + ?: throw IllegalArgumentException("Could not find an argument named '$name' on ${shortName.asString()}") + +fun KSAnnotated.findAnnotation(annotationName: AnnotationName): KSAnnotation { + return annotations.single { it.isA(annotationName) } +} + +fun KSAnnotated.findAnnotationOrNull(annotationName: AnnotationName): KSAnnotation? { + return annotations.singleOrNull { it.isA(annotationName) } +} + +fun KSAnnotated.isAnnotationPresent(annotationName: AnnotationName): Boolean { + return annotations.any { it.isA(annotationName) } +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/Strings.kt b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/Strings.kt new file mode 100644 index 000000000..d9903ee7c --- /dev/null +++ b/spring-properties-processor/src/main/kotlin/io/github/freya022/botcommands/properties/processor/utils/Strings.kt @@ -0,0 +1,6 @@ +package io.github.freya022.botcommands.properties.processor.utils + +fun String.tryAppendDot(): String = when { + this.endsWith('.') -> this + else -> "$this." +} \ No newline at end of file diff --git a/spring-properties-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/spring-properties-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 000000000..c2832f964 --- /dev/null +++ b/spring-properties-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +io.github.freya022.botcommands.properties.processor.SpringPropertiesProcessorProvider \ No newline at end of file diff --git a/src/main/java/io/github/freya022/botcommands/api/$BCInfo.java b/src/main/java/io/github/freya022/botcommands/api/$BCInfo.java index b2e19cf2e..a67dd8c99 100644 --- a/src/main/java/io/github/freya022/botcommands/api/$BCInfo.java +++ b/src/main/java/io/github/freya022/botcommands/api/$BCInfo.java @@ -3,30 +3,20 @@ import java.time.Instant; public class $BCInfo { - public static final Instant BUILD_TIME; - public static final String VERSION_MAJOR = "%%version-major%%"; - public static final String VERSION_MINOR = "%%version-minor%%"; - public static final String VERSION_REVISION = "%%version-revision%%"; - public static final String VERSION_CLASSIFIER = "%%version-classifier%%"; + public static final Instant BUILD_TIME = Instant.ofEpochMilli(Long.parseLong("@build-time@")); + public static final String VERSION_MAJOR = "@version-major@"; + public static final String VERSION_MINOR = "@version-minor@"; + public static final String VERSION_REVISION = "@version-revision@"; + public static final String VERSION_CLASSIFIER = "@version-classifier@"; public static final String GITHUB = "https://github.com/freya022/BotCommands"; /** May be "null", may also be a full commit hash in Jitpack builds */ - public static final String BRANCH_NAME = "%%branch-name%%"; + public static final String BRANCH_NAME = "@branch-name@"; /** May be "null" */ - public static final String COMMIT_HASH = "%%commit-hash%%"; - public static final String BUILD_JDA_VERSION = "%%build-jda-version%%"; + public static final String COMMIT_HASH = "@commit-hash@"; + public static final String BUILD_JDA_VERSION = "@build-jda-version@"; @SuppressWarnings("ConstantConditions") public static final String VERSION = "%s.%s.%s%s%s".formatted(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, - VERSION_CLASSIFIER == null ? "" : "-" + VERSION_CLASSIFIER, + VERSION_CLASSIFIER.equals("null") ? "" : "-" + VERSION_CLASSIFIER, COMMIT_HASH.equals("null") ? "" : "_" + COMMIT_HASH); - - static { - Instant tmpBuildTime; - try { - tmpBuildTime = Instant.ofEpochMilli(Long.parseLong("%%build-time%%")); - } catch (NumberFormatException e) { //Can happen on IJ builds, ig - tmpBuildTime = Instant.now(); - } - BUILD_TIME = tmpBuildTime; - } } diff --git a/src/main/kotlin/io/github/freya022/botcommands/api/core/JDAService.kt b/src/main/kotlin/io/github/freya022/botcommands/api/core/JDAService.kt index 548a918dc..ab27957a8 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/api/core/JDAService.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/api/core/JDAService.kt @@ -1,10 +1,11 @@ package io.github.freya022.botcommands.api.core import dev.minn.jda.ktx.events.CoroutineEventManager +import io.github.freya022.botcommands.api.core.JDAService.Companion.defaultIntents import io.github.freya022.botcommands.api.core.JDAService.Companion.getDefaultRestConfig +import io.github.freya022.botcommands.api.core.JDAService.Companion.getDefaultRestRateLimiter import io.github.freya022.botcommands.api.core.annotations.BEventListener import io.github.freya022.botcommands.api.core.conditions.RequiredIntents -import io.github.freya022.botcommands.api.core.config.JDAConfiguration import io.github.freya022.botcommands.api.core.events.BReadyEvent import io.github.freya022.botcommands.api.core.events.InjectedJDAEvent import io.github.freya022.botcommands.api.core.requests.PriorityGlobalRestRateLimiter @@ -60,7 +61,7 @@ import javax.annotation.CheckReturnValue * * #### Spring support * Spring users must set their gateway intents and cache flags using properties, - * named `jda.intents` and `jda.cacheFlags` respectively, also available in [JDAConfiguration]. + * named `jda.intents` and `jda.cacheFlags` respectively, also available in `JDAConfiguration`. * * @see createJDA * @see InterfacedService @InterfacedService diff --git a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BConfig.kt b/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BConfig.kt index a40df0e09..747c69665 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BConfig.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BConfig.kt @@ -119,7 +119,7 @@ interface BConfig { } @ConfigDSL -class BConfigBuilder internal constructor() : BConfig { +class BConfigBuilder : BConfig { override val packages: MutableSet = HashSet() override val classes: MutableSet> = HashSet() @@ -272,8 +272,7 @@ class BConfigBuilder internal constructor() : BConfig { componentsConfig.apply(block) } - @JvmSynthetic - internal fun build(): BConfig { + fun build(): BConfig { val logger = KotlinLogging.loggerOf() if (disableExceptionsInDMs) logger.info { "Disabled sending exception in bot owners DMs" } diff --git a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BDatabaseConfig.kt b/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BDatabaseConfig.kt index 8553a2282..7d38283e0 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BDatabaseConfig.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/api/core/config/BDatabaseConfig.kt @@ -5,10 +5,10 @@ import io.github.freya022.botcommands.api.core.service.annotations.InjectedServi import io.github.freya022.botcommands.internal.core.config.ConfigDSL import io.github.freya022.botcommands.internal.core.config.ConfigurationValue import kotlinx.coroutines.debug.DebugProbes +import java.time.Duration as JavaDuration import kotlin.time.Duration import kotlin.time.toJavaDuration import kotlin.time.toKotlinDuration -import java.time.Duration as JavaDuration @InjectedService interface BDatabaseConfig { diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/JDAServiceMismatchChecker.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/JDAServiceMismatchChecker.kt index 94c24e3ba..cc2fa62e4 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/JDAServiceMismatchChecker.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/JDAServiceMismatchChecker.kt @@ -2,13 +2,10 @@ package io.github.freya022.botcommands.internal.core import io.github.freya022.botcommands.api.core.JDAService import io.github.freya022.botcommands.api.core.annotations.BEventListener -import io.github.freya022.botcommands.api.core.config.JDAConfiguration import io.github.freya022.botcommands.api.core.events.InjectedJDAEvent import io.github.freya022.botcommands.api.core.service.annotations.BService -import io.github.freya022.botcommands.internal.utils.reference import io.github.oshai.kotlinlogging.KotlinLogging import net.dv8tion.jda.api.requests.GatewayIntent -import org.springframework.stereotype.Component private val logger = KotlinLogging.logger { } @@ -52,37 +49,3 @@ internal object JDAServiceMismatchChecker { private fun Collection.withOverlappingIntents(): Set = GatewayIntent.getIntents(GatewayIntent.getRaw(this)) - -// Spring checks are slightly different, we want to tell the user to move them to their application environment, -// so the checks are consistent with condition annotations, as they can only check the environment -@Component -internal class SpringJDAServiceMismatchChecker { - @BEventListener - internal fun onJDA(event: InjectedJDAEvent, jdaConfiguration: JDAConfiguration, jdaService: JDAService) { - val environmentIntents = jdaConfiguration.intents - val jdaServiceIntents = jdaService.intents - if (environmentIntents != jdaServiceIntents) { - logger.warn { - """ - The intents given in JDAService and the environment should be the same! - Environment intents: ${environmentIntents.sorted()} - JDAService intents: ${jdaServiceIntents.sorted()} - Hint: you should get your intents from ${JDAConfiguration::intents.reference} - """.trimIndent() - } - } - - val environmentCacheFlags = jdaConfiguration.cacheFlags - val jdaServiceCacheFlags = jdaService.cacheFlags - if (environmentCacheFlags != jdaServiceCacheFlags) { - logger.warn { - """ - The cache flags given in JDAService and the environment should be the same! - Environment cache flags: ${environmentCacheFlags.sorted()} - JDAService cache flags: ${jdaServiceCacheFlags.sorted()} - Hint: you should get your caches flags from ${JDAConfiguration::cacheFlags.reference} - """.trimIndent() - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/Version.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/Version.kt index c56d237e4..99378ede1 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/Version.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/Version.kt @@ -6,13 +6,13 @@ import io.github.oshai.kotlinlogging.KotlinLogging import net.dv8tion.jda.api.JDAInfo // This really needs to not be critical -internal class Version private constructor( +class Version private constructor( val minor: Int, val major: Int, val revision: Int, val classifier: Classifier? ) : Comparable { - internal data class Classifier(val name: String, val version: Int) : Comparable { + data class Classifier internal constructor(val name: String, val version: Int) : Comparable { override fun compareTo(other: Classifier): Int { if (name != other.name) return classifierIndex().compareTo(other.classifierIndex()) return version.compareTo(other.version) diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigurationAnnotations.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigurationAnnotations.kt index 6ab240331..d47ca1211 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigurationAnnotations.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/config/ConfigurationAnnotations.kt @@ -5,7 +5,7 @@ import org.intellij.lang.annotations.Language @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented -internal annotation class ConfigurationValue( +annotation class ConfigurationValue( val path: String, val defaultValue: String = "", @Language("Java", prefix = "", suffix = " x = null;") val type: String = "java.lang.Byte", @@ -14,7 +14,7 @@ internal annotation class ConfigurationValue( @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented -internal annotation class DeprecatedValue( +annotation class DeprecatedValue( val reason: String, val level: DeprecationLevel = DeprecationLevel.WARNING, val replacement: String = "", @@ -27,4 +27,4 @@ internal annotation class DeprecatedValue( @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.SOURCE) -internal annotation class IgnoreDefaultValue \ No newline at end of file +annotation class IgnoreDefaultValue \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/AbstractBotCommandsBootstrap.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/AbstractBotCommandsBootstrap.kt index 4be42ca36..e3573821f 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/AbstractBotCommandsBootstrap.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/AbstractBotCommandsBootstrap.kt @@ -14,16 +14,16 @@ import kotlinx.coroutines.runBlocking import kotlin.time.DurationUnit import kotlin.time.measureTime -internal abstract class AbstractBotCommandsBootstrap(protected val config: BConfig) : BotCommandsBootstrap { +abstract class AbstractBotCommandsBootstrap(protected val config: BConfig) : BotCommandsBootstrap { protected val logger = objectLogger() - internal fun init() { + protected fun init() { measure("Scanned reflection metadata") { ReflectionMetadata.runScan(config, this) } } - internal fun loadContext() = runBlocking { + fun loadContext() = runBlocking { measure("Completed BotCommands loading events") { serviceContainer.getService().apply { setStatus(BContext.Status.PRE_LOAD) diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/ClassAnnotationsMap.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/ClassAnnotationsMap.kt index cc2c51632..514030bea 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/ClassAnnotationsMap.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/ClassAnnotationsMap.kt @@ -52,6 +52,6 @@ internal class SpringClassAnnotationsMap( val beansWithAnnotation = context.getBeansWithAnnotation(clazz.java) if (beansWithAnnotation.isEmpty()) return null - return beansWithAnnotation.keys.mapTo(hashSetOf()) { context.getType(it).kotlin } + return beansWithAnnotation.keys.mapTo(hashSetOf()) { context.getType(it)!!.kotlin } } } \ No newline at end of file diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/InstantiableServices.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/InstantiableServices.kt index 41bb1df51..e1d51d44c 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/InstantiableServices.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/core/service/InstantiableServices.kt @@ -1,6 +1,5 @@ package io.github.freya022.botcommands.internal.core.service -import io.github.freya022.botcommands.api.core.config.BConfig import io.github.freya022.botcommands.api.core.service.ServiceError.ErrorType.* import io.github.freya022.botcommands.api.core.service.annotations.BService import io.github.freya022.botcommands.api.core.service.annotations.InterfacedService @@ -15,48 +14,16 @@ import io.github.freya022.botcommands.internal.utils.throwArgument import io.github.freya022.botcommands.internal.utils.throwInternal import io.github.freya022.botcommands.internal.utils.throwState import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.context.ApplicationContext -import org.springframework.stereotype.Service import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation private val logger = KotlinLogging.logger { } // Don't use InterfacedService, having it sealed + ServiceType is enough, saves unnecessary checks and logs -internal sealed interface InstantiableServices { +interface InstantiableServices { fun getAllPrimaryTypes(): Set> } -@Service -internal class SpringInstantiableServices internal constructor( - private val config: BConfig, - private val applicationContext: ApplicationContext -) : InstantiableServices { - override fun getAllPrimaryTypes(): Set> { - return applicationContext.beanDefinitionNames - .asSequence() - .map { beanName -> - val type = applicationContext.getType(beanName) - if (type != null) { - type - } else { - logger.debug { "Creating bean '$beanName' as no type is available" } - applicationContext.getBean(beanName).javaClass - } - } - .filter { type -> - if (config.packages.any { type.packageName.startsWith(it) }) - return@filter true - if (type.packageName.startsWith("io.github.freya022.botcommands")) - return@filter true - if (type in config.classes) - return@filter true - return@filter false - } - .mapTo(hashSetOf()) { it.kotlin } - } -} - @BService(priority = Int.MAX_VALUE) @ServiceType(InstantiableServices::class) @RequiresDefaultInjection diff --git a/src/main/kotlin/io/github/freya022/botcommands/internal/utils/References.kt b/src/main/kotlin/io/github/freya022/botcommands/internal/utils/References.kt index 50fc34f31..386f33778 100644 --- a/src/main/kotlin/io/github/freya022/botcommands/internal/utils/References.kt +++ b/src/main/kotlin/io/github/freya022/botcommands/internal/utils/References.kt @@ -5,8 +5,7 @@ import kotlin.jvm.internal.CallableReference import kotlin.reflect.KClass import kotlin.reflect.KProperty -@PublishedApi -internal val KProperty<*>.reference: String +val KProperty<*>.reference: String get() { val callableReference = (this as? CallableReference) ?: throwInternal("Referenced field doesn't seem to be compiler generated, exact type: ${this::class}") diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index cfa787ee1..000000000 --- a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -io.github.freya022.botcommands.autoconfigure.BotCommandsAutoConfiguration \ No newline at end of file