diff --git a/src/tools/permissionstree/PermissionNodesGatherer.java b/src/tools/permissionstree/PermissionNodesGatherer.java
new file mode 100644
index 000000000..5da8841c9
--- /dev/null
+++ b/src/tools/permissionstree/PermissionNodesGatherer.java
@@ -0,0 +1,113 @@
+package permissionstree;
+
+import fr.xephi.authme.permission.AdminPermission;
+import fr.xephi.authme.permission.PermissionNode;
+import fr.xephi.authme.permission.PlayerPermission;
+import fr.xephi.authme.util.StringUtils;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Gatherer to generate up-to-date lists of the AuthMe permission nodes.
+ */
+public class PermissionNodesGatherer {
+
+ /** The folder in which the implementations of {@link PermissionNode} reside. */
+ private static final String PERMISSION_NODE_SOURCE_FOLDER =
+ "src/main/java/fr/xephi/authme/permission/";
+
+ /**
+ * Regular expression that should match the JavaDoc comment above an enum, including
+ * the name of the enum value. The first group (i.e. {@code \\1}) should be the JavaDoc description;
+ * the second group should contain the enum value.
+ */
+ private static final Pattern JAVADOC_WITH_ENUM_PATTERN = Pattern.compile(
+ "/\\*\\*\\s+\\*" // Match starting '/**' and the '*' on the next line
+ + "(.*?)\\s+\\*/" // Capture everything until we encounter '*/'
+ + "\\s+([A-Z_]+)\\("); // Match the enum name (e.g. 'LOGIN'), until before the first '('
+
+ /**
+ * Return a sorted collection of all permission nodes.
+ *
+ * @return AuthMe permission nodes sorted alphabetically
+ */
+ public Set gatherNodes() {
+ Set nodes = new TreeSet<>();
+ for (PermissionNode perm : PlayerPermission.values()) {
+ nodes.add(perm.getNode());
+ }
+ for (PermissionNode perm : AdminPermission.values()) {
+ nodes.add(perm.getNode());
+ }
+ return nodes;
+ }
+
+ /**
+ * Return a sorted collection of all permission nodes, including its JavaDoc description.
+ *
+ * @return Ordered map whose keys are the permission nodes and the values the associated JavaDoc
+ */
+ public Map gatherNodesWithJavaDoc() {
+ Map result = new TreeMap<>();
+ addDescriptionsForClass(PlayerPermission.class, result);
+ addDescriptionsForClass(AdminPermission.class, result);
+ return result;
+ }
+
+ private & PermissionNode> void addDescriptionsForClass(Class clazz,
+ Map descriptions) {
+ String classSource = getSourceForClass(clazz);
+ Map sourceDescriptions = extractJavaDocFromSource(classSource);
+
+ for (T perm : EnumSet.allOf(clazz)) {
+ String description = sourceDescriptions.get(perm.name());
+ if (description == null) {
+ System.out.println("Note: Could not retrieve description for "
+ + clazz.getSimpleName() + "#" + perm.name());
+ description = "";
+ }
+ descriptions.put(perm.getNode(), description.trim());
+ }
+ }
+
+ private static Map extractJavaDocFromSource(String source) {
+ Map allMatches = new HashMap<>();
+ Matcher matcher = JAVADOC_WITH_ENUM_PATTERN.matcher(source);
+ while (matcher.find()) {
+ String description = matcher.group(1);
+ String enumValue = matcher.group(2);
+ allMatches.put(enumValue, description);
+ }
+ return allMatches;
+ }
+
+ /**
+ * Return the Java source code for the given implementation of {@link PermissionNode}.
+ *
+ * @param clazz The clazz to the get the source for
+ * @param The concrete class
+ * @return Source code of the file
+ */
+ private static & PermissionNode> String getSourceForClass(Class clazz) {
+ String classFile = PERMISSION_NODE_SOURCE_FOLDER + clazz.getSimpleName() + ".java";
+ Charset cs = Charset.forName("utf-8");
+ try {
+ return StringUtils.join("\n",
+ Files.readAllLines(Paths.get(classFile), cs));
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to get the source for class '" + clazz.getSimpleName() + "'");
+ }
+ }
+
+}
diff --git a/src/tools/permissionstree/PermissionNodesListCreater.java b/src/tools/permissionstree/PermissionNodesListCreater.java
deleted file mode 100644
index bfc1a3b73..000000000
--- a/src/tools/permissionstree/PermissionNodesListCreater.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package permissionstree;
-
-import fr.xephi.authme.permission.AdminPermission;
-import fr.xephi.authme.permission.PermissionNode;
-import fr.xephi.authme.permission.PlayerPermission;
-
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * Generate all permission nodes like a tree.
- */
-public class PermissionNodesListCreater {
-
- public Set gatherNodes() {
- Set nodes = new TreeSet<>();
- for (PermissionNode perm : PlayerPermission.values()) {
- nodes.add(perm.getNode());
- }
- for (PermissionNode perm : AdminPermission.values()) {
- nodes.add(perm.getNode());
- }
- return nodes;
- }
-
-}
diff --git a/src/tools/permissionstree/PermissionsListWriter.java b/src/tools/permissionstree/PermissionsListWriter.java
index 2f3e40f59..7d1cd1c26 100644
--- a/src/tools/permissionstree/PermissionsListWriter.java
+++ b/src/tools/permissionstree/PermissionsListWriter.java
@@ -4,6 +4,7 @@ import fr.xephi.authme.util.StringUtils;
import utils.CommentType;
import utils.GeneratedFileWriter;
+import java.util.Map;
import java.util.Scanner;
import java.util.Set;
@@ -18,14 +19,15 @@ public class PermissionsListWriter {
public static void main(String[] args) {
// Ask if result should be written to file
Scanner scanner = new Scanner(System.in);
- System.out.println("Write to file? [y = yes]");
- String answer = scanner.next();
- boolean writeToFile = "y".equalsIgnoreCase(answer);
+ System.out.println("Include description? [Enter 'n' for no]");
+ boolean includeDescription = !matches("n", scanner);
+
+ System.out.println("Write to file? [Enter 'y' for yes]");
+ boolean writeToFile = matches("y", scanner);
+ scanner.close();
// Generate connections and output or write
- PermissionNodesListCreater creater = new PermissionNodesListCreater();
- Set nodes = creater.gatherNodes();
- String output = StringUtils.join("\n", nodes);
+ String output = generatedOutput(includeDescription);
if (writeToFile) {
GeneratedFileWriter.createGeneratedFile(PERMISSIONS_TREE_FILE, output, CommentType.YML);
@@ -34,4 +36,27 @@ public class PermissionsListWriter {
}
}
+ private static String generatedOutput(boolean includeDescription) {
+ PermissionNodesGatherer creater = new PermissionNodesGatherer();
+ if (!includeDescription) {
+ Set nodes = creater.gatherNodes();
+ return StringUtils.join("\n", nodes);
+ }
+
+ Map permissions = creater.gatherNodesWithJavaDoc();
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry entry : permissions.entrySet()) {
+ sb.append(entry.getKey())
+ .append(": ")
+ .append(entry.getValue())
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
+ private static boolean matches(String answer, Scanner sc) {
+ String userInput = sc.nextLine();
+ return answer.equalsIgnoreCase(userInput);
+ }
+
}