diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1d39407 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,17 @@ +name: Build +on: [push] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: Build with Gradle + uses: gradle/gradle-build-action@v2 + with: + arguments: build diff --git a/build.gradle.kts b/build.gradle.kts index 2fe55d5..510de78 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { `kotlin-dsl` kotlin("plugin.serialization") version "1.6.21" @@ -33,22 +31,27 @@ gradlePlugin { implementationClass = "lgbt.mystic.foundation.concrete.ConcreteRootPlugin" } - create("concrete-project") { - id = "lgbt.mystic.foundation.concrete-project" - implementationClass = "lgbt.mystic.foundation.concrete.ConcreteProjectPlugin" + create("concrete-plugin") { + id = "lgbt.mystic.foundation.concrete-plugin" + implementationClass = "lgbt.mystic.foundation.concrete.ConcretePluginPlugin" + } + + create("concrete-library") { + id = "lgbt.mystic.foundation.concrete-library" + implementationClass = "lgbt.mystic.foundation.concrete.ConcreteLibraryPlugin" } } } java { - val version = JavaVersion.toVersion("1.8") + val version = JavaVersion.toVersion("11") sourceCompatibility = version targetCompatibility = version } -tasks.withType { +tasks.compileKotlin { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } } diff --git a/sample/hello-world/build.gradle.kts b/sample/hello-world/build.gradle.kts deleted file mode 100644 index 0c3aca3..0000000 --- a/sample/hello-world/build.gradle.kts +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id("lgbt.mystic.foundation.concrete-project") -} diff --git a/samples/mixed/build.gradle.kts b/samples/mixed/build.gradle.kts new file mode 100644 index 0000000..e69de29 diff --git a/sample/.gitignore b/samples/mixed/bukkit-plugins/.gitignore similarity index 100% rename from sample/.gitignore rename to samples/mixed/bukkit-plugins/.gitignore diff --git a/samples/mixed/bukkit-plugins/build.gradle.kts b/samples/mixed/bukkit-plugins/build.gradle.kts new file mode 100644 index 0000000..0bc25ac --- /dev/null +++ b/samples/mixed/bukkit-plugins/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("lgbt.mystic.foundation.concrete-root") +} + +concrete { + minecraftServerPath.set("server") + paperVersionGroup.set("1.19") + paperApiVersion.set("1.19-R0.1-SNAPSHOT") + acceptServerEula.set(true) +} diff --git a/samples/mixed/bukkit-plugins/common-library/build.gradle.kts b/samples/mixed/bukkit-plugins/common-library/build.gradle.kts new file mode 100644 index 0000000..10925e6 --- /dev/null +++ b/samples/mixed/bukkit-plugins/common-library/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("lgbt.mystic.foundation.concrete-library") +} diff --git a/samples/mixed/bukkit-plugins/common-library/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/common/CommonExtensions.kt b/samples/mixed/bukkit-plugins/common-library/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/common/CommonExtensions.kt new file mode 100644 index 0000000..befb662 --- /dev/null +++ b/samples/mixed/bukkit-plugins/common-library/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/common/CommonExtensions.kt @@ -0,0 +1,6 @@ +package lgbt.mystic.foundation.concrete.sample.common + +import org.bukkit.plugin.java.JavaPlugin + +fun JavaPlugin.logOnEnable(name: String) = slF4JLogger.info("Enabled $name") +fun JavaPlugin.logOnDisable(name: String) = slF4JLogger.info("Disabled $name") diff --git a/samples/mixed/bukkit-plugins/goodbye-world/build.gradle.kts b/samples/mixed/bukkit-plugins/goodbye-world/build.gradle.kts new file mode 100644 index 0000000..e545dd3 --- /dev/null +++ b/samples/mixed/bukkit-plugins/goodbye-world/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("lgbt.mystic.foundation.concrete-plugin") +} + +dependencies { + implementation(project(":bukkit-plugins:common-library")) +} diff --git a/samples/mixed/bukkit-plugins/goodbye-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/goodbyeworld/GoodbyeWorldPlugin.kt b/samples/mixed/bukkit-plugins/goodbye-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/goodbyeworld/GoodbyeWorldPlugin.kt new file mode 100644 index 0000000..d0cd43f --- /dev/null +++ b/samples/mixed/bukkit-plugins/goodbye-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/goodbyeworld/GoodbyeWorldPlugin.kt @@ -0,0 +1,15 @@ +package lgbt.mystic.foundation.concrete.sample.goodbyeworld + +import lgbt.mystic.foundation.concrete.sample.common.logOnDisable +import lgbt.mystic.foundation.concrete.sample.common.logOnEnable +import org.bukkit.plugin.java.JavaPlugin + +class GoodbyeWorldPlugin : JavaPlugin() { + override fun onEnable() { + logOnEnable("Goodbye World") + } + + override fun onDisable() { + logOnDisable("Goodbye World") + } +} diff --git a/samples/mixed/bukkit-plugins/goodbye-world/src/main/resources/plugin.yml b/samples/mixed/bukkit-plugins/goodbye-world/src/main/resources/plugin.yml new file mode 100644 index 0000000..d108f04 --- /dev/null +++ b/samples/mixed/bukkit-plugins/goodbye-world/src/main/resources/plugin.yml @@ -0,0 +1,9 @@ +name: GoodbyeWorld +version: '${version}' +main: lgbt.mystic.foundation.concrete.sample.goodbyeworld.GoodbyeWorldPlugin +api-version: 1.18 +prefix: GoodbyeWorld +load: STARTUP +authors: + - kubelet + - kexec diff --git a/samples/mixed/bukkit-plugins/hello-world/build.gradle.kts b/samples/mixed/bukkit-plugins/hello-world/build.gradle.kts new file mode 100644 index 0000000..faa219d --- /dev/null +++ b/samples/mixed/bukkit-plugins/hello-world/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("lgbt.mystic.foundation.concrete-plugin") +} + +dependencies { + implementation(project(":other-library")) + implementation(project(":bukkit-plugins:common-library")) +} diff --git a/samples/mixed/bukkit-plugins/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt b/samples/mixed/bukkit-plugins/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt new file mode 100644 index 0000000..f071e08 --- /dev/null +++ b/samples/mixed/bukkit-plugins/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt @@ -0,0 +1,16 @@ +package lgbt.mystic.foundation.concrete.sample.helloworld + +import lgbt.mystic.foundation.concrete.other.OtherLibrary +import lgbt.mystic.foundation.concrete.sample.common.logOnDisable +import lgbt.mystic.foundation.concrete.sample.common.logOnEnable +import org.bukkit.plugin.java.JavaPlugin + +class HelloWorldPlugin : JavaPlugin() { + override fun onEnable() { + logOnEnable(OtherLibrary.HELLO_WORLD) + } + + override fun onDisable() { + logOnDisable(OtherLibrary.HELLO_WORLD) + } +} diff --git a/sample/hello-world/src/main/resources/plugin.yml b/samples/mixed/bukkit-plugins/hello-world/src/main/resources/plugin.yml similarity index 100% rename from sample/hello-world/src/main/resources/plugin.yml rename to samples/mixed/bukkit-plugins/hello-world/src/main/resources/plugin.yml diff --git a/sample/gradle/wrapper/gradle-wrapper.jar b/samples/mixed/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from sample/gradle/wrapper/gradle-wrapper.jar rename to samples/mixed/gradle/wrapper/gradle-wrapper.jar diff --git a/sample/gradle/wrapper/gradle-wrapper.properties b/samples/mixed/gradle/wrapper/gradle-wrapper.properties similarity index 92% rename from sample/gradle/wrapper/gradle-wrapper.properties rename to samples/mixed/gradle/wrapper/gradle-wrapper.properties index 41dfb87..aa991fc 100644 --- a/sample/gradle/wrapper/gradle-wrapper.properties +++ b/samples/mixed/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/sample/gradlew b/samples/mixed/gradlew similarity index 100% rename from sample/gradlew rename to samples/mixed/gradlew diff --git a/sample/gradlew.bat b/samples/mixed/gradlew.bat similarity index 100% rename from sample/gradlew.bat rename to samples/mixed/gradlew.bat diff --git a/samples/mixed/other-library/build.gradle.kts b/samples/mixed/other-library/build.gradle.kts new file mode 100644 index 0000000..0f14d1b --- /dev/null +++ b/samples/mixed/other-library/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + `java-library` +} diff --git a/samples/mixed/other-library/src/main/java/lgbt/mystic/foundation/concrete/other/OtherLibrary.java b/samples/mixed/other-library/src/main/java/lgbt/mystic/foundation/concrete/other/OtherLibrary.java new file mode 100644 index 0000000..1327d68 --- /dev/null +++ b/samples/mixed/other-library/src/main/java/lgbt/mystic/foundation/concrete/other/OtherLibrary.java @@ -0,0 +1,5 @@ +package lgbt.mystic.foundation.concrete.other; + +public class OtherLibrary { + public static final String HELLO_WORLD = "Hello World"; +} diff --git a/samples/mixed/settings.gradle.kts b/samples/mixed/settings.gradle.kts new file mode 100644 index 0000000..ffe8853 --- /dev/null +++ b/samples/mixed/settings.gradle.kts @@ -0,0 +1,6 @@ +includeBuild("../..") +include(":bukkit-plugins") +include(":bukkit-plugins:hello-world") +include(":bukkit-plugins:goodbye-world") +include(":bukkit-plugins:common-library") +include(":other-library") diff --git a/samples/simple/.gitignore b/samples/simple/.gitignore new file mode 100644 index 0000000..ab39cbc --- /dev/null +++ b/samples/simple/.gitignore @@ -0,0 +1 @@ +server/ diff --git a/sample/build.gradle.kts b/samples/simple/build.gradle.kts similarity index 100% rename from sample/build.gradle.kts rename to samples/simple/build.gradle.kts diff --git a/samples/simple/gradle/wrapper/gradle-wrapper.jar b/samples/simple/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..41d9927 Binary files /dev/null and b/samples/simple/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/simple/gradle/wrapper/gradle-wrapper.properties b/samples/simple/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..aa991fc --- /dev/null +++ b/samples/simple/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/samples/simple/gradlew b/samples/simple/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/samples/simple/gradlew @@ -0,0 +1,234 @@ +#!/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. +# + +############################################################################## +# +# 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/master/subprojects/plugins/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 + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# 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"' + +# 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=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# 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 + which java >/dev/null 2>&1 || 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 + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + 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 + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# 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/samples/simple/gradlew.bat b/samples/simple/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/samples/simple/gradlew.bat @@ -0,0 +1,89 @@ +@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 + +@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=. +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%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="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! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/simple/hello-world/build.gradle.kts b/samples/simple/hello-world/build.gradle.kts new file mode 100644 index 0000000..af92cdf --- /dev/null +++ b/samples/simple/hello-world/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("lgbt.mystic.foundation.concrete-plugin") +} diff --git a/sample/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt b/samples/simple/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt similarity index 100% rename from sample/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt rename to samples/simple/hello-world/src/main/kotlin/lgbt/mystic/foundation/concrete/sample/helloworld/HelloWorldPlugin.kt diff --git a/samples/simple/hello-world/src/main/resources/plugin.yml b/samples/simple/hello-world/src/main/resources/plugin.yml new file mode 100644 index 0000000..3eadd8a --- /dev/null +++ b/samples/simple/hello-world/src/main/resources/plugin.yml @@ -0,0 +1,9 @@ +name: HelloWorld +version: '${version}' +main: lgbt.mystic.foundation.concrete.sample.helloworld.HelloWorldPlugin +api-version: 1.18 +prefix: HelloWorld +load: STARTUP +authors: + - kubelet + - kexec diff --git a/sample/settings.gradle.kts b/samples/simple/settings.gradle.kts similarity index 52% rename from sample/settings.gradle.kts rename to samples/simple/settings.gradle.kts index e73b51e..6d5a5a6 100644 --- a/sample/settings.gradle.kts +++ b/samples/simple/settings.gradle.kts @@ -1,2 +1,2 @@ -includeBuild("..") +includeBuild("../..") include(":hello-world") diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteExtension.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteExtension.kt index 57c393d..8cee80a 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteExtension.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteExtension.kt @@ -6,4 +6,5 @@ interface ConcreteExtension { val paperVersionGroup: Property val paperApiVersion: Property val minecraftServerPath: Property + val acceptServerEula: Property } diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteLibraryPlugin.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteLibraryPlugin.kt new file mode 100644 index 0000000..8ad4c32 --- /dev/null +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteLibraryPlugin.kt @@ -0,0 +1,3 @@ +package lgbt.mystic.foundation.concrete + +class ConcreteLibraryPlugin : ConcreteProjectPlugin() diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcretePluginPlugin.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcretePluginPlugin.kt new file mode 100644 index 0000000..697cf33 --- /dev/null +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcretePluginPlugin.kt @@ -0,0 +1,31 @@ +package lgbt.mystic.foundation.concrete + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.get +import org.gradle.language.jvm.tasks.ProcessResources + +@Suppress("UnstableApiUsage") +class ConcretePluginPlugin : ConcreteProjectPlugin() { + override fun apply(project: Project) { + super.apply(project) + + project.plugins.apply("com.github.johnrengelman.shadow") + + project.tasks.find("processResources")!!.apply { + val props = mapOf("version" to project.version.toString()) + inputs.properties(props) + filteringCharset = "UTF-8" + filesMatching("plugin.yml") { + expand(props) + } + } + + project.shadowJarTask!!.apply { + archiveClassifier.set("plugin") + } + + project.tasks.addTaskDependency("assemble", "shadowJar") + + project.concreteRootProject.tasks["setupPaperServer"].dependsOn(project.tasks["shadowJar"]) + } +} diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteProjectPlugin.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteProjectPlugin.kt index 2e66842..1fc19a2 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteProjectPlugin.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteProjectPlugin.kt @@ -1,21 +1,16 @@ package lgbt.mystic.foundation.concrete -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension -import org.gradle.api.tasks.compile.JavaCompile -import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.repositories import org.gradle.kotlin.dsl.withType -import org.gradle.language.jvm.tasks.ProcessResources import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.net.URI -@Suppress("UnstableApiUsage") -class ConcreteProjectPlugin : Plugin { +open class ConcreteProjectPlugin : Plugin { override fun apply(project: Project) { val versionWithBuild = if (System.getenv("CI_PIPELINE_IID") != null) { project.rootProject.version.toString() + ".${System.getenv("CI_PIPELINE_IID")}" @@ -23,11 +18,10 @@ class ConcreteProjectPlugin : Plugin { "DEV" } + project.version = versionWithBuild + project.plugins.apply("org.jetbrains.kotlin.jvm") project.plugins.apply("org.jetbrains.kotlin.plugin.serialization") - project.plugins.apply("com.github.johnrengelman.shadow") - - project.version = versionWithBuild project.repositories { maven { @@ -36,8 +30,7 @@ class ConcreteProjectPlugin : Plugin { } } - val paperApiVersion = project.rootProject.extensions.getByType().paperApiVersion.get() - + val paperApiVersion = project.concreteRootExtension.paperApiVersion.get() project.dependencies.add("compileOnly", "io.papermc.paper:paper-api:${paperApiVersion}") project.extensions.getByType().apply { @@ -46,21 +39,6 @@ class ConcreteProjectPlugin : Plugin { targetCompatibility = javaVersion } - (project.tasks.getByName("processResources") as ProcessResources).apply { - val props = mapOf("version" to project.version.toString()) - inputs.properties(props) - filteringCharset = "UTF-8" - filesMatching("plugin.yml") { - expand(props) - } - } - - (project.tasks["shadowJar"] as ShadowJar).apply { - archiveClassifier.set("plugin") - } - - project.tasks["assemble"].dependsOn(project.tasks["shadowJar"]) - project.tasks.withType().forEach { it.apply { kotlinOptions.apply { @@ -68,7 +46,5 @@ class ConcreteProjectPlugin : Plugin { } } } - - project.rootProject.tasks["setupPaperServer"].dependsOn(project.tasks["shadowJar"]) } } diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteRootPlugin.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteRootPlugin.kt index 0c04a14..e17518d 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteRootPlugin.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/ConcreteRootPlugin.kt @@ -7,7 +7,7 @@ import org.gradle.kotlin.dsl.create class ConcreteRootPlugin : Plugin { override fun apply(project: Project) { - project.apply(plugin = "java") + project.apply(plugin = "base") project.extensions.create("concrete") val setupPaperServer = project.tasks.create("setupPaperServer") val runPaperServer = project.tasks.create("runPaperServer") diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/PaperVersionClient.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/PaperVersionClient.kt index 9a62ef3..d2ea7c8 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/PaperVersionClient.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/PaperVersionClient.kt @@ -7,7 +7,7 @@ import java.net.http.HttpRequest import java.net.http.HttpResponse class PaperVersionClient( - val client: HttpClient = HttpClient.newHttpClient(), + private val client: HttpClient = HttpClient.newHttpClient(), private val gson: Gson = Globals.gson ) { private val apiBaseUrl = URI.create("https://papermc.io/api/v2/") diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/RunPaperServer.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/RunPaperServer.kt index ea76298..c0dbfad 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/RunPaperServer.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/RunPaperServer.kt @@ -1,6 +1,7 @@ package lgbt.mystic.foundation.concrete import org.gradle.api.DefaultTask +import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.getByType import java.io.File @@ -11,6 +12,12 @@ open class RunPaperServer : DefaultTask() { outputs.upToDateWhen { false } } + @get:Input + var additionalServerArguments = mutableListOf() + + @get:Input + var disableServerGui = true + @TaskAction fun runPaperServer() { val concrete = project.extensions.getByType() @@ -22,7 +29,14 @@ open class RunPaperServer : DefaultTask() { project.javaexec { classpath(paperJarFile.absolutePath) workingDir(minecraftServerDirectory) - args("nogui") + + val allServerArguments = mutableListOf() + allServerArguments.addAll(additionalServerArguments) + if (disableServerGui) { + allServerArguments.add("nogui") + } + + args(allServerArguments) mainClass.set(mainClassName) } } diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/SetupPaperServer.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/SetupPaperServer.kt index 65a5cc7..b0742fa 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/SetupPaperServer.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/SetupPaperServer.kt @@ -1,6 +1,5 @@ package lgbt.mystic.foundation.concrete -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.DefaultTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction @@ -8,6 +7,7 @@ import org.gradle.api.tasks.options.Option import org.gradle.kotlin.dsl.getByType import java.io.File import java.nio.file.Files +import java.util.Properties open class SetupPaperServer : DefaultTask() { init { @@ -16,7 +16,7 @@ open class SetupPaperServer : DefaultTask() { @get:Input @set:Option(option = "update", description = "Update Paper Server") - var shouldUpdatePaperServer = false + var shouldUpdatePaperServer = true private val paperVersionClient = PaperVersionClient() @@ -40,20 +40,32 @@ open class SetupPaperServer : DefaultTask() { paperPluginsDirectory.mkdirs() } - for (project in project.allprojects) { - if (!project.isPluginProject()) { - continue - } - - val task = project.tasks.getByName("shadowJar") as ShadowJar + for (project in project.findPluginProjects()) { + val task = project.shadowJarTask!! val pluginJarFile = task.outputs.files.first() val pluginLinkFile = paperPluginsDirectory.resolve("${project.name}.jar") pluginLinkFile.delete() Files.createSymbolicLink(pluginLinkFile.toPath(), pluginJarFile.toPath()) } + + if (concrete.acceptServerEula.isPresent && concrete.acceptServerEula.get()) { + val writer = minecraftServerDirectory.resolve("eula.txt").bufferedWriter() + val properties = Properties() + properties.setProperty("eula", "true") + properties.store(writer, "Written by Concrete") + writer.close() + } } private fun downloadLatestBuild(paperVersionGroup: String, paperJarFile: File) { + if (project.gradle.startParameter.isOffline) { + if (!paperJarFile.exists()) { + throw RuntimeException("Offline mode is enabled and Paper has not been downloaded.") + } else { + logger.lifecycle("Offline mode is enabled, skipping Paper update.") + return + } + } val builds = paperVersionClient.getVersionBuilds(paperVersionGroup) val build = builds.last() val download = build.downloads["application"]!! diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/SmartDownloader.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/SmartDownloader.kt index 2f00988..6116338 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/SmartDownloader.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/SmartDownloader.kt @@ -14,9 +14,9 @@ class SmartDownloader( val hashResult = checkLocalFileHash() if (hashResult != HashResult.ValidHash) { downloadRemoteFile() - return false + return true } - return true + return false } private fun downloadRemoteFile() { diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/UpdateManifestTask.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/UpdateManifestTask.kt index aeaaeb4..eaebf7b 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/UpdateManifestTask.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/UpdateManifestTask.kt @@ -12,7 +12,7 @@ open class UpdateManifestTask : DefaultTask() { val updateFile = manifestsDir.resolve("update.json") val rootPath = project.rootProject.rootDir.toPath() val updateManifest = project.findPluginProjects().mapNotNull { project -> - val paths = project.shadowJarOutputs.allFilesRelativeToPath(rootPath) + val paths = project.shadowJarOutputs!!.allFilesRelativeToPath(rootPath) if (paths.isNotEmpty()) { project.name to mapOf( "version" to project.version, diff --git a/src/main/kotlin/lgbt/mystic/foundation/concrete/extensions.kt b/src/main/kotlin/lgbt/mystic/foundation/concrete/extensions.kt index 273ad88..0448c93 100644 --- a/src/main/kotlin/lgbt/mystic/foundation/concrete/extensions.kt +++ b/src/main/kotlin/lgbt/mystic/foundation/concrete/extensions.kt @@ -1,16 +1,70 @@ package lgbt.mystic.foundation.concrete +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Project +import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskOutputs import java.nio.file.FileSystems import java.nio.file.Path -fun Project.isPluginProject() = project.tasks.names.contains("shadowJar") -fun Project.findPluginProjects() = rootProject.allprojects.filter { project -> project.isPluginProject() } +/** + * Checks if the project has the [ConcretePluginPlugin] applied. + */ +internal fun Project.isPluginProject() = plugins.hasPlugin(ConcretePluginPlugin::class.java) -val Project.shadowJarOutputs: TaskOutputs - get() = project.tasks.getByName("shadowJar").outputs +/** + * Finds all projects in the project's hierarchy that are plugins. + */ +internal fun Project.findPluginProjects() = allprojects.filter { project -> project.isPluginProject() } -fun TaskOutputs.allFilesRelativeToPath(root: Path): List = files.map { root.relativize(it.toPath()) } +internal fun TaskContainer.addTaskDependency(dependent: String, dependency: String) { + getByName(dependent).dependsOn(getByName(dependency)) +} -fun Path.toUnixString() = toString().replace(FileSystems.getDefault().separator, "/") +internal inline fun TaskContainer.find(name: String) = + findByName(name) as T? + +internal val Project.shadowJarTask: ShadowJar? + get() = project.tasks.find("shadowJar") + +internal val Project.shadowJarOutputs: TaskOutputs? + get() = shadowJarTask?.outputs + +internal val Project.concreteRootExtension: ConcreteExtension + get() = findTargetParent( + valid = { extensions.findByType(ConcreteExtension::class.java) != null }, + extract = { extensions.findByType(ConcreteExtension::class.java)!! }, + error = { "Failed to find concrete root. Did you apply the concrete root plugin?" } + ) + +/** + * Finds the concrete root project, which is the first project in the project hierarchy + * that has the concrete extension. + */ +internal val Project.concreteRootProject: Project + get() = findTargetParent( + valid = { extensions.findByType(ConcreteExtension::class.java) != null }, + extract = { this }, + error = { "Failed to find concrete root. Did you apply the concrete root plugin?" } + ) + +/** + * Scans a project hierarchy looking for a project matching the criteria specified in [valid]. + * If found, [extract] is called and the result is returned. If no matching project is found, [error] is called + * and passed to RuntimeException as an error string. + */ +internal fun Project.findTargetParent(valid: Project.() -> Boolean, extract: Project.() -> T, error: () -> String): T { + if (valid(this)) { + return extract(this) + } + + if (parent != null) { + return parent!!.findTargetParent(valid, extract, error) + } + + throw RuntimeException(error()) +} + +internal fun TaskOutputs.allFilesRelativeToPath(root: Path): List = files.map { root.relativize(it.toPath()) } + +internal fun Path.toUnixString() = toString().replace(FileSystems.getDefault().separator, "/")