Skip to content

Commit

Permalink
refactor: move common classes into common package + add: module dep…
Browse files Browse the repository at this point in the history
…endency checker + fix: the `production work` in `works module` can't work if `resource world module` is disabled.
  • Loading branch information
sakurawald committed Jul 21, 2024
1 parent 0054a33 commit 684710f
Show file tree
Hide file tree
Showing 19 changed files with 236 additions and 20 deletions.
15 changes: 12 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,22 @@ tasks.register('generateDocs') {
}
tasks.modrinthSyncBody.dependsOn(generateDocs)

tasks.register('generateMixinRegistry') {
tasks.register('checkMixinRegistryTest') {
outputs.upToDateWhen { false }
test {
filter {
includeTestsMatching 'MixinRegistryGenTest.generate'
includeTestsMatching 'CheckMixinRegistryTest.test'
}
}
}
tasks.compileJava.dependsOn(generateMixinRegistry)
tasks.compileJava.dependsOn(checkMixinRegistryTest)

tasks.register('checkModuleDependencyTest') {
outputs.upToDateWhen { false }
test {
filter {
includeTestsMatching 'CheckModuleDependencyTest.test'
}
}
}
tasks.compileJava.dependsOn(checkModuleDependencyTest)
2 changes: 1 addition & 1 deletion fuji-fabric.wiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.sakurawald.generator.structure;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.*;

@Data
@AllArgsConstructor
public class Reference {
String definition;
List<String> reference;

public static List<Reference> reduce(List<Reference> references) {
// merge
Map<String, Reference> map = new HashMap<>();
for (Reference reference : references) {
map.putIfAbsent(reference.definition, reference);
map.get(reference.definition).getReference().addAll(reference.reference);
}

//reduce
for (Reference reference : map.values()) {
Set<String> set = new HashSet<>(reference.reference);
reference.reference.clear();
reference.reference.addAll(set);
}

return map.values().stream().toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sakurawald.module.initializer.chat.mention;
package io.github.sakurawald.module.common.job;

import io.github.sakurawald.config.Configs;
import io.github.sakurawald.config.model.ConfigModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("LombokGetterMayBeUsed")
@Slf4j
public class BossBarManager {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport;
package io.github.sakurawald.module.common.random_teleport;

import java.util.OptionalInt;
import net.minecraft.world.chunk.Chunk;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport;
package io.github.sakurawald.module.common.random_teleport;

import java.util.Optional;
import java.util.OptionalInt;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport;
package io.github.sakurawald.module.common.random_teleport;

import com.google.common.base.Stopwatch;
import io.github.sakurawald.Fuji;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import io.github.sakurawald.config.model.ChatModel;
import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.module.initializer.chat.display.DisplayHelper;
import io.github.sakurawald.module.initializer.chat.mention.MentionPlayersJob;
import io.github.sakurawald.module.common.job.MentionPlayersJob;
import io.github.sakurawald.util.CommandUtil;
import io.github.sakurawald.util.DateUtil;
import io.github.sakurawald.util.PermissionUtil;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.github.sakurawald.module.initializer.newbie_welcome;

import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport;
import io.github.sakurawald.module.common.random_teleport.RandomTeleport;
import io.github.sakurawald.util.MessageUtil;
import net.minecraft.server.network.ServerPlayerEntity;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import io.github.sakurawald.config.Configs;
import io.github.sakurawald.config.model.ConfigModel;
import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport;
import io.github.sakurawald.module.common.random_teleport.RandomTeleport;
import io.github.sakurawald.module.initializer.resource_world.interfaces.DimensionOptionsMixinInterface;
import io.github.sakurawald.module.common.accessor.SimpleRegistryMixinInterface;
import io.github.sakurawald.util.CommandUtil;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io.github.sakurawald.config.Configs;
import io.github.sakurawald.config.model.ConfigModel;
import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.module.mixin.top_chunks.ThreadedAnvilChunkStorageMixin;
import io.github.sakurawald.module.mixin._internal.low_level.ThreadedAnvilChunkStorageMixin;
import io.github.sakurawald.util.MessageUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.module.initializer.chat.mention.MentionPlayersJob;
import io.github.sakurawald.module.common.job.MentionPlayersJob;
import io.github.sakurawald.util.CommandUtil;
import io.github.sakurawald.util.MessageUtil;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import io.github.sakurawald.module.initializer.works.WorksCache;
import io.github.sakurawald.module.common.gui.ConfirmGui;
import io.github.sakurawald.module.common.gui.InputSignGui;
import io.github.sakurawald.module.mixin.top_chunks.ThreadedAnvilChunkStorageMixin;
import io.github.sakurawald.module.mixin._internal.low_level.ThreadedAnvilChunkStorageMixin;
import io.github.sakurawald.util.DateUtil;
import io.github.sakurawald.util.GuiUtil;
import io.github.sakurawald.util.MessageUtil;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sakurawald.module.mixin.top_chunks;
package io.github.sakurawald.module.mixin._internal.low_level;

import net.minecraft.server.world.ChunkHolder;
import net.minecraft.server.world.ServerChunkLoadingManager;
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/io/github/sakurawald/util/JsonUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.sakurawald.util;

import com.google.gson.JsonObject;
import lombok.experimental.UtilityClass;

@UtilityClass
public class JsonUtil {

public static boolean existsNode(JsonObject root, String path){
String[] nodes = path.split("\\.");
for (int i = 0; i < nodes.length - 1; i++) {
String node = nodes[i];
if (!root.has(node)) return false;
if (!root.isJsonObject()) return false;

root = root.getAsJsonObject(node);
}

return root.has(nodes[nodes.length - 1]);
}
}
2 changes: 1 addition & 1 deletion src/main/resources/fuji.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"language.ServerPlayerMixin",
"chat.PlayerListMixin",
"_internal.low_level.SimpleRegistryMixin",
"top_chunks.ThreadedAnvilChunkStorageMixin",
"_internal.low_level.ThreadedAnvilChunkStorageMixin",
"command_permission.CommandNodeAccessor",
"anti_build.EntityMixin",
"carpet.fake_player_manager.PlayerListMixin",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package generator;
package checker;

import com.google.gson.*;
import io.github.sakurawald.module.ModuleManager;
Expand All @@ -12,7 +12,7 @@
import java.util.ArrayList;
import java.util.List;

public class MixinRegistryGenTest {
public class CheckMixinRegistryTest {

private List<JsonElement> collectJsonArray(JsonElement jsonElement, String key) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
Expand All @@ -29,7 +29,7 @@ private List<String> collectMixins(JsonElement jsonElement, String key) {

@SneakyThrows
@Test
void generate() {
void test() {

/* read file */
File file = new File("src/main/resources/fuji.mixins.json");
Expand Down
156 changes: 156 additions & 0 deletions src/test/java/checker/CheckModuleDependencyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package checker;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.sakurawald.Fuji;
import io.github.sakurawald.config.model.ConfigModel;
import io.github.sakurawald.generator.structure.Reference;
import io.github.sakurawald.util.JsonUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.Test;

import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class CheckModuleDependencyTest {

public static final String COMMON = "common";
private static final Pattern importPattern = Pattern.compile("import\\s+(\\S+);");
private static final Pattern staticImportPattern = Pattern.compile("import\\s+static\\s+(\\S+)\\.\\S+;");
private static final Pattern moduleNamePattern = Pattern.compile("io\\.github\\.sakurawald\\.module\\.(?:initializer|mixin)\\.(\\S+)\\.\\S+;?");
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();

private List<String> extractMatches(Pattern pattern, String text, int group) {
Matcher matcher = pattern.matcher(text);

List<String> ret = new ArrayList<>();
while (matcher.find()) {
ret.add(matcher.group(group));
}

return ret;
}

@SneakyThrows
private List<String> getRefClassNameList(String path) {
String text = FileUtils.readFileToString(Path.of(path).toFile(), Charset.defaultCharset());

List<String> ret = new ArrayList<>();
ret.addAll(extractMatches(importPattern, text, 1));
ret.addAll(extractMatches(staticImportPattern, text, 1));
return ret;
}

private List<String> filterClassName(List<String> className, String prefix) {
return className.stream().filter(s -> s.startsWith(prefix)).toList();
}

private Path getCodebasePath() {
return Path.of("src", "main", "java");
}

private Reference makeClassRef(Path file) {
String className = file.toString().replace("/", ".").replace("src.main.java.", "").replace(".java", "");
List<String> refClassNameList = getRefClassNameList(file.toString());

// filter only project class ref
refClassNameList = filterClassName(refClassNameList, Fuji.class.getPackage().getName());

return new Reference(className, refClassNameList);
}

private String extractModuleName(String className) {
List<String> moduleNameList = extractMatches(moduleNamePattern, className, 1);
if (moduleNameList.isEmpty()) {
return COMMON;
}
return moduleNameList.getFirst();
}

private boolean isRealModulePath(String moduleName) {
JsonElement root = gson.toJsonTree(new ConfigModel());
return JsonUtil.existsNode((JsonObject) root, "modules.%s.enable".formatted(moduleName));
}

private boolean isSibling(String a, String b) {
String[] A = a.split("\\.");
String[] B = b.split("\\.");

if (A.length != B.length) return false;
for (int i = 0; i < A.length - 1; i++) {
if (!A[i].equals(B[i])) return false;
}
return true;
}

private Reference makeModuleRef(Reference classRef) {
String definition = extractModuleName(classRef.getDefinition());
List<String> reference = new ArrayList<>();
for (String ref : classRef.getReference()) {
String str = extractModuleName(ref);
// skip -> common reference
if (str.equals(COMMON)) continue;
// skip -> self reference
if (definition.equals(str) || definition.startsWith(str)) continue;
if (str.startsWith(definition) && !isRealModulePath(str)) continue;
if (isSibling(definition, str) && !isRealModulePath(definition) && !isRealModulePath(str)) continue;
// skip -> reference internal module
if (str.startsWith("_")) continue;

reference.add(str);
}

if (definition.equals(COMMON)) return null;
if (reference.isEmpty()) return null;
return new Reference(definition, reference);
}


@SneakyThrows
private List<Reference> walk(Path path) {
/* per class reference */
List<Reference> refs = new ArrayList<>();
Files.walkFileTree(path, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
Reference reference = makeModuleRef(makeClassRef(file));
if (reference != null) {
refs.add(reference);
}

return FileVisitResult.CONTINUE;
}
});

/* reduce */
return Reference.reduce(refs);
}

@Test
void test() {
CheckModuleDependencyTest gen = new CheckModuleDependencyTest();

List<Reference> refs = gen.walk(gen.getCodebasePath());

System.out.println("\n=== module dependency analysis ===");
refs.forEach(System.out::println);
System.out.println();

if (!refs.isEmpty()) {
throw new RuntimeException("module dependency is not pure !");
}
}
}

0 comments on commit 684710f

Please sign in to comment.