From 51fe32055e92ef5c78bb5362727479f373212e7a Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 11:47:13 -0600 Subject: [PATCH 1/7] Use Reflections library rather than Jar class scanning --- build.gradle | 37 ++++++--- .../github/syst3ms/skriptparser/Parser.java | 83 ++++++++++++------- .../syst3ms/skriptparser/util/FileUtils.java | 8 ++ 3 files changed, 89 insertions(+), 39 deletions(-) diff --git a/build.gradle b/build.gradle index 0619f6fc..c8733a47 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,13 @@ plugins { - id "java" - id "application" + id 'com.gradleup.shadow' version '9.0.0-beta12' + id 'application' + id 'java' } -mainClassName = "io.github.syst3ms.skriptparser.Parser" +compileTestJava.options.encoding = 'UTF-8' +compileJava.options.encoding = 'UTF-8' -sourceCompatibility = 1.11 +mainClassName = "io.github.syst3ms.skriptparser.Parser" repositories { mavenCentral() @@ -16,12 +18,25 @@ test { } dependencies { - implementation "org.jetbrains:annotations:15.0" - implementation group: "com.google.code.findbugs", name: "jsr305", version: "3.0.2" - testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.4.1" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.1" - testImplementation "junit:junit:4.12" - testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.1" + implementation (group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2') + implementation (group: 'org.jetbrains', name: 'annotations', version: '26.0.2') + + shadow (group: 'org.reflections', name: 'reflections', version: '0.10.2') + shadow (group: 'org.javassist', name: 'javassist', version: '3.30.2-GA') + shadow (group: 'com.google.code.gson', name: 'gson', version: '2.13.0') + + testRuntimeOnly (group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '5.11.4') + testRuntimeOnly (group: 'org.junit.jupiter', name:'junit-jupiter-engine', version: '5.11.4') + + testImplementation (group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.11.4') + testImplementation (group: 'com.google.code.gson', name: 'gson', version: '2.13.0') + testImplementation (group: 'junit', name: 'junit', version: '4.13.2') +} + +java { + withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } jar { @@ -30,4 +45,4 @@ jar { "Implementation-Title": "skript-parser", "Implementation-Version": "alpha") } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/syst3ms/skriptparser/Parser.java b/src/main/java/io/github/syst3ms/skriptparser/Parser.java index b3b3d9c0..3f6a3725 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/Parser.java +++ b/src/main/java/io/github/syst3ms/skriptparser/Parser.java @@ -7,7 +7,9 @@ import io.github.syst3ms.skriptparser.registration.SkriptAddon; import io.github.syst3ms.skriptparser.registration.SkriptRegistration; import io.github.syst3ms.skriptparser.util.ConsoleColors; -import io.github.syst3ms.skriptparser.util.FileUtils; +import org.jetbrains.annotations.Nullable; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -23,12 +25,12 @@ import java.util.Calendar; import java.util.List; import java.util.jar.JarFile; -import java.util.jar.Manifest; public class Parser { + public static final String CONSOLE_FORMAT = "[%tT] %s: %s%n"; - private static SkriptRegistration registration; + private static SkriptRegistration registration; private static List logs; public static void main(String[] args) { @@ -69,49 +71,72 @@ public static void main(String[] args) { * @param standalone whether the parser tries to load addons (standalone) or not (library) */ public static void init(String[] mainPackages, String[] subPackages, String[] programArgs, boolean standalone) { + init(mainPackages, subPackages, programArgs, standalone, null); + } + + /** + * Starts the parser. + * @param mainPackages packages inside which all subpackages containing classes to load may be present. Doesn't need + * to contain Skript's own main packages. + * @param subPackages the subpackages inside which classes to load may be present. Doesn't need to contain Skript's + * own subpackages. + * @param programArgs any other program arguments (typically from the command line) + * @param standalone whether the parser tries to load addons (standalone) or not (library) + * @param parserPath the main path to the parser, will be used to get the addons folder. If null, the path will be inferred from the parser's location. + */ + public static void init(String[] mainPackages, String[] subPackages, String[] programArgs, boolean standalone, @Nullable Path parserPath) { Skript skript = new Skript(programArgs); registration = new SkriptRegistration(skript); DefaultRegistration.register(); - // Make sure Skript loads properly no matter what + + // Ensure Skript loads first mainPackages = Arrays.copyOf(mainPackages, mainPackages.length + 1); mainPackages[mainPackages.length - 1] = "io.github.syst3ms.skriptparser"; + + // Combine main and sub-packages List sub = new ArrayList<>(); sub.addAll(Arrays.asList(subPackages)); sub.addAll(Arrays.asList("expressions", "effects", "event", "lang", "sections", "tags")); subPackages = sub.toArray(new String[0]); - try { - for (String mainPackage : mainPackages) { - FileUtils.loadClasses(FileUtils.getJarFile(Parser.class), mainPackage, subPackages); + List allPackages = new ArrayList<>(List.of(mainPackages)); + for (String subPackage : subPackages) { + for (String main : mainPackages) { + allPackages.add(main + "." + subPackage); } + } + + try { + // Load all classes in the specified packages + new Reflections(allPackages.toArray(new String[0]), Scanners.SubTypes.filterResultsBy(s -> true)) + .getSubTypesOf(Object.class) + .forEach(clazz -> { + try { + Class.forName(clazz.getName(), true, Parser.class.getClassLoader()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + }); + + // Load addons if standalone mode is enabled if (standalone) { - Path parserPath = Paths.get(Parser.class - .getProtectionDomain() - .getCodeSource() - .getLocation() - .toURI() - ); - Path addonFolderPath = Paths.get(parserPath.getParent().toString(), "addons"); + if (parserPath == null) { + parserPath = Paths.get(Parser.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); + } + Path addonFolderPath = parserPath.getParent().resolve("addons"); if (Files.isDirectory(addonFolderPath)) { Files.walk(addonFolderPath) .filter(Files::isRegularFile) - .filter((filePath) -> filePath.toString().endsWith(".jar")) - .forEach((Path addonPath) -> { - try { - URLClassLoader child = new URLClassLoader( - new URL[]{addonPath.toUri().toURL()}, - Parser.class.getClassLoader() - ); - JarFile jar = new JarFile(addonPath.toString()); - Manifest manifest = jar.getManifest(); - String main = manifest.getMainAttributes().getValue("Main-Class"); - if (main != null) { - Class mainClass = Class.forName(main, true, child); + .filter(filePath -> filePath.toString().endsWith(".jar")) + .forEach(addonPath -> { + try (JarFile jar = new JarFile(addonPath.toString())) { + URLClassLoader child = new URLClassLoader(new URL[]{addonPath.toUri().toURL()}, Parser.class.getClassLoader()); + String mainClassName = jar.getManifest().getMainAttributes().getValue("Main-Class"); + if (mainClassName != null) { try { + Class mainClass = Class.forName(mainClassName, true, child); Method init = mainClass.getDeclaredMethod("initAddon"); init.invoke(null); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } finally { - jar.close(); } } } catch (IOException | ClassNotFoundException e) { @@ -125,6 +150,8 @@ public static void init(String[] mainPackages, String[] subPackages, String[] pr System.err.println("Error while loading classes:"); e.printStackTrace(); } + + // Log registration results Calendar time = Calendar.getInstance(); logs = registration.register(); if (!logs.isEmpty()) { diff --git a/src/main/java/io/github/syst3ms/skriptparser/util/FileUtils.java b/src/main/java/io/github/syst3ms/skriptparser/util/FileUtils.java index 7a61e3b7..caed354f 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/util/FileUtils.java +++ b/src/main/java/io/github/syst3ms/skriptparser/util/FileUtils.java @@ -17,6 +17,7 @@ * Utility functions for file parsing */ public class FileUtils { + public static final Pattern LEADING_WHITESPACE_PATTERN = Pattern.compile("(\\s+)\\S.*"); public static final String MULTILINE_SYNTAX_TOKEN = "\\"; private static final String OS_SEPARATOR = FileSystems.getDefault().getSeparator(); @@ -134,7 +135,9 @@ public static String removeExtension(String s) { * @param rootPackage a root package * @param subPackages a list of all subpackages of the root package, in which classes will be loaded * @throws IOException if an I/O error has occurred + * @deprecated use the Reflections library for classpath scanning and loading instead */ + @Deprecated public static void loadClasses(File jarFile, String rootPackage, String... subPackages) throws IOException { if (jarFile.isDirectory()) throw new IllegalArgumentException("The provided file is actually a directory!"); @@ -174,7 +177,9 @@ public static void loadClasses(File jarFile, String rootPackage, String... subPa * @param rootPackage a root package * @param subPackages a list of all subpackages of the root package, in which classes will be leadied * @throws IOException if an I/O error has occurred + * @deprecated use the Reflections library for classpath scanning and loading instead */ + @Deprecated public static void loadClasses(Path directory, String rootPackage, String... subPackages) throws IOException { if (!directory.toFile().isDirectory()) throw new IllegalArgumentException("The provided file isn't a directory!"); @@ -209,8 +214,11 @@ public static void loadClasses(Path directory, String rootPackage, String... sub * * @param cla the class * @return the JAR file containing the class + * @deprecated not all projects that uses skript-parser are JAR files, so this method may not work as expected */ + @Deprecated public static File getJarFile(Class cla) throws URISyntaxException { return new File(cla.getProtectionDomain().getCodeSource().getLocation().toURI()); } + } From 41e0997b20f971c28e2106db0d9a6123ed55ee62 Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 12:02:23 -0600 Subject: [PATCH 2/7] Update github deprecated actions --- .github/workflows/build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3dfc119b..584a95e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,16 +10,17 @@ jobs: building: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: validate gradle wrapper uses: gradle/wrapper-validation-action@v1 - name: Set up JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: - java-version: 11 + java-version: 17 + distribution: 'microsoft' - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} From 3785a85a425b1bdbd9d1fa49e23c24900f226d9c Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 12:04:28 -0600 Subject: [PATCH 3/7] Update github deprecated actions --- .github/workflows/test.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 77c4b493..03f5a9ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,18 +11,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: [11, 13] + java-version: [11, 13, 17] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: validate gradle wrapper uses: gradle/wrapper-validation-action@v1 - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v1 with: java-version: ${{ matrix.java-version }} + distribution: 'microsoft' - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} From f95ad2e1d48e31ac2c40f8fabf49760b17c3e7a1 Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 12:05:39 -0600 Subject: [PATCH 4/7] Update github deprecated actions --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 584a95e7..c72196d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: run: ./gradlew test - name: Upload Nightly Build - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: success() with: name: skript-nightly From def012d897e571df95777b863c37f8f8700ae11f Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 12:08:04 -0600 Subject: [PATCH 5/7] Update github deprecated actions --- .github/workflows/test.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03f5a9ed..42eab185 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,17 +9,14 @@ on: jobs: testing: runs-on: ubuntu-latest - strategy: - matrix: - java-version: [11, 13, 17] steps: - uses: actions/checkout@v4 - name: validate gradle wrapper uses: gradle/wrapper-validation-action@v1 - - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v1 + - name: Set up JDK + uses: actions/setup-java@v4 with: - java-version: ${{ matrix.java-version }} + java-version: 17 distribution: 'microsoft' - name: Cache Gradle packages From 56936351e95e249c16f1b9b6827c3510262d0979 Mon Sep 17 00:00:00 2001 From: TheLimeGlass Date: Sun, 13 Apr 2025 14:43:18 -0600 Subject: [PATCH 6/7] Avoid adding just the main package --- .../github/syst3ms/skriptparser/Parser.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/github/syst3ms/skriptparser/Parser.java b/src/main/java/io/github/syst3ms/skriptparser/Parser.java index 3f6a3725..7415d2a4 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/Parser.java +++ b/src/main/java/io/github/syst3ms/skriptparser/Parser.java @@ -25,6 +25,7 @@ import java.util.Calendar; import java.util.List; import java.util.jar.JarFile; +import java.util.stream.Stream; public class Parser { @@ -89,25 +90,17 @@ public static void init(String[] mainPackages, String[] subPackages, String[] pr registration = new SkriptRegistration(skript); DefaultRegistration.register(); - // Ensure Skript loads first - mainPackages = Arrays.copyOf(mainPackages, mainPackages.length + 1); - mainPackages[mainPackages.length - 1] = "io.github.syst3ms.skriptparser"; - - // Combine main and sub-packages - List sub = new ArrayList<>(); - sub.addAll(Arrays.asList(subPackages)); - sub.addAll(Arrays.asList("expressions", "effects", "event", "lang", "sections", "tags")); - subPackages = sub.toArray(new String[0]); - List allPackages = new ArrayList<>(List.of(mainPackages)); - for (String subPackage : subPackages) { - for (String main : mainPackages) { - allPackages.add(main + "." + subPackage); - } - } + String[] allPackages = Stream.concat( + Stream.of("expressions", "effects", "event", "lang", "sections", "structures", "tags") + .map(subPackage -> "io.github.syst3ms.skriptparser." + subPackage), + Stream.of(subPackages) + .flatMap(subPackage -> Stream.of(mainPackages) + .map(main -> main + "." + subPackage)) + ).toArray(String[]::new); try { // Load all classes in the specified packages - new Reflections(allPackages.toArray(new String[0]), Scanners.SubTypes.filterResultsBy(s -> true)) + new Reflections(allPackages, Scanners.SubTypes.filterResultsBy(s -> true)) .getSubTypesOf(Object.class) .forEach(clazz -> { try { From 696a77f8f14d9160674251eae27551ed29f996a6 Mon Sep 17 00:00:00 2001 From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:07:55 -0600 Subject: [PATCH 7/7] Update Parser.java --- .../github/syst3ms/skriptparser/Parser.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/github/syst3ms/skriptparser/Parser.java b/src/main/java/io/github/syst3ms/skriptparser/Parser.java index 7415d2a4..0c94d9ef 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/Parser.java +++ b/src/main/java/io/github/syst3ms/skriptparser/Parser.java @@ -25,7 +25,6 @@ import java.util.Calendar; import java.util.List; import java.util.jar.JarFile; -import java.util.stream.Stream; public class Parser { @@ -90,13 +89,20 @@ public static void init(String[] mainPackages, String[] subPackages, String[] pr registration = new SkriptRegistration(skript); DefaultRegistration.register(); - String[] allPackages = Stream.concat( - Stream.of("expressions", "effects", "event", "lang", "sections", "structures", "tags") - .map(subPackage -> "io.github.syst3ms.skriptparser." + subPackage), - Stream.of(subPackages) - .flatMap(subPackage -> Stream.of(mainPackages) - .map(main -> main + "." + subPackage)) - ).toArray(String[]::new); + List allPackages = new ArrayList<>(); + + // Add default subpackages + List defaultSubPackages = Arrays.asList("expressions", "effects", "event", "lang", "sections", "structures", "tags"); + for (String subPackage : defaultSubPackages) { + allPackages.add("io.github.syst3ms.skriptparser." + subPackage); + } + + // Add user-defined subpackages + for (String mainPackage : mainPackages) { + for (String subPackage : subPackages) { + allPackages.add(mainPackage + "." + subPackage); + } + } try { // Load all classes in the specified packages