From 935e9892c4f5676f585385fdd8f94e4a3ade839c Mon Sep 17 00:00:00 2001
From: ljacqu <ljacqu@users.noreply.github.com>
Date: Thu, 10 Dec 2015 18:11:31 +0100
Subject: [PATCH] Tools - Create message files verifier (work in progress)

- Create utility to test the message files for any unknown or missing message keys
---
 src/tools/messages/MessageFileVerifier.java   | 78 +++++++++++++++++++
 .../messages/MessagesVerifierRunner.java      | 70 +++++++++++++++++
 src/tools/messages/README.md                  |  2 +
 src/tools/utils/FileUtils.java                | 18 +++++
 src/tools/utils/ToolsConstants.java           |  2 +
 5 files changed, 170 insertions(+)
 create mode 100644 src/tools/messages/MessageFileVerifier.java
 create mode 100644 src/tools/messages/MessagesVerifierRunner.java
 create mode 100644 src/tools/messages/README.md

diff --git a/src/tools/messages/MessageFileVerifier.java b/src/tools/messages/MessageFileVerifier.java
new file mode 100644
index 000000000..f3b37525f
--- /dev/null
+++ b/src/tools/messages/MessageFileVerifier.java
@@ -0,0 +1,78 @@
+package messages;
+
+import fr.xephi.authme.output.MessageKey;
+import utils.FileUtils;
+import utils.ToolsConstants;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Verifies that a message file has all keys as given in {@link MessageKey}.
+ */
+public class MessageFileVerifier {
+
+    public static final String MESSAGES_FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/";
+    private static final String NEW_LINE = "\n";
+
+    private final String messagesFile;
+    private final Map<String, String> defaultMessages;
+
+    public MessageFileVerifier(Map<String, String> defaultMessages, String messagesFile) {
+        this.messagesFile = messagesFile;
+        this.defaultMessages = defaultMessages;
+    }
+
+    public void verify(boolean addMissingKeys) {
+        Set<String> messageKeys = getAllMessageKeys();
+        List<String> fileLines = FileUtils.readLinesFromFile(messagesFile);
+        for (String line : fileLines) {
+            // Skip comments and empty lines
+            if (!line.startsWith("#") && !line.trim().isEmpty()) {
+                handleMessagesLine(line, messageKeys);
+            }
+        }
+
+        if (messageKeys.isEmpty()) {
+            System.out.println("Found all message keys");
+        } else {
+            handleMissingKeys(messageKeys, addMissingKeys);
+        }
+    }
+
+    private void handleMessagesLine(String line, Set<String> messageKeys) {
+        if (line.indexOf(':') == -1) {
+            System.out.println("Skipping line in unknown format: '" + line + "'");
+            return;
+        }
+
+        final String key = line.substring(0, line.indexOf(':'));
+        if (messageKeys.contains(key)) {
+            messageKeys.remove(key);
+        } else {
+            System.out.println("Warning: Unknown key '" + key + "' for line '" + line + "'");
+        }
+    }
+
+    private void handleMissingKeys(Set<String> missingKeys, boolean addMissingKeys) {
+        for (String key : missingKeys) {
+            if (addMissingKeys) {
+                String defaultMessage = defaultMessages.get(key);
+                FileUtils.appendToFile(messagesFile, NEW_LINE + key + ":" + defaultMessage);
+                System.out.println("Added missing key '" + key + "' to file");
+            } else {
+                System.out.println("Error: Missing key '" + key + "'");
+            }
+        }
+    }
+
+    private static Set<String> getAllMessageKeys() {
+        Set<String> messageKeys = new HashSet<>(MessageKey.values().length);
+        for (MessageKey key : MessageKey.values()) {
+            messageKeys.add(key.getKey());
+        }
+        return messageKeys;
+    }
+}
diff --git a/src/tools/messages/MessagesVerifierRunner.java b/src/tools/messages/MessagesVerifierRunner.java
new file mode 100644
index 000000000..ff50e5055
--- /dev/null
+++ b/src/tools/messages/MessagesVerifierRunner.java
@@ -0,0 +1,70 @@
+package messages;
+
+import utils.FileUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * TODO: ljacqu write JavaDoc
+ */
+public final class MessagesVerifierRunner {
+
+    private MessagesVerifierRunner() {
+    }
+
+    public static void main(String[] args) {
+        final Map<String, String> defaultMessages = constructDefaultMessages();
+        final List<File> messagesFiles = getMessagesFiles();
+
+        if (messagesFiles.isEmpty()) {
+            throw new RuntimeException("Error getting messages file: list of files is empty");
+        }
+
+        for (File file : messagesFiles) {
+            System.out.println("Verifying '" + file.getName() + "'");
+            MessageFileVerifier messageFileVerifier = new MessageFileVerifier(defaultMessages, file.getAbsolutePath());
+            messageFileVerifier.verify(false);
+            System.out.println();
+        }
+    }
+
+    private static Map<String, String> constructDefaultMessages() {
+        String defaultMessagesFile = MessageFileVerifier.MESSAGES_FOLDER + "messages_en.yml";
+        List<String> lines = FileUtils.readLinesFromFile(defaultMessagesFile);
+        Map<String, String> messages = new HashMap<>(lines.size());
+        for (String line : lines) {
+            if (line.startsWith("#") || line.trim().isEmpty()) {
+                continue;
+            }
+            if (line.indexOf(':') == -1) {
+                System.out.println("Warning! Unknown format in default messages file for line '" + line + "'");
+            } else {
+                String key = line.substring(0, line.indexOf(':'));
+                messages.put(key, line.substring(line.indexOf(':') + 1)); // fixme: may throw exception
+            }
+        }
+        return messages;
+    }
+
+    private static List<File> getMessagesFiles() {
+        final Pattern messageFilePattern = Pattern.compile("messages_[a-z]{2,3}\\.yml");
+        File folder = new File(MessageFileVerifier.MESSAGES_FOLDER);
+        File[] files = folder.listFiles();
+        if (files == null) {
+            throw new RuntimeException("Could not read files from folder '" + folder.getName() + "'");
+        }
+
+        List<File> messageFiles = new ArrayList<>();
+        for (File file : files) {
+            if (messageFilePattern.matcher(file.getName()).matches()) {
+                messageFiles.add(file);
+            }
+        }
+        return messageFiles;
+    }
+}
diff --git a/src/tools/messages/README.md b/src/tools/messages/README.md
new file mode 100644
index 000000000..594558a4a
--- /dev/null
+++ b/src/tools/messages/README.md
@@ -0,0 +1,2 @@
+## Messages
+Verifies the messages files and adds any missing indices with the English content as default.
diff --git a/src/tools/utils/FileUtils.java b/src/tools/utils/FileUtils.java
index fb88ae27c..5ad5ab25e 100644
--- a/src/tools/utils/FileUtils.java
+++ b/src/tools/utils/FileUtils.java
@@ -4,6 +4,8 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -31,6 +33,14 @@ public final class FileUtils {
         }
     }
 
+    public static void appendToFile(String outputFile, String contents) {
+        try {
+            Files.write(Paths.get(outputFile), contents.getBytes(), StandardOpenOption.APPEND);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to append to file '" + outputFile + "'", e);
+        }
+    }
+
     public static String readFromFile(String file) {
         try {
             return new String(Files.readAllBytes(Paths.get(file)), CHARSET);
@@ -39,6 +49,14 @@ public final class FileUtils {
         }
     }
 
+    public static List<String> readLinesFromFile(String file) {
+        try {
+            return Files.readAllLines(Paths.get(file), CHARSET);
+        } catch (IOException e) {
+            throw new RuntimeException("Could not read from file '" + file + "'", e);
+        }
+    }
+
     public static String readFromToolsFile(String file) {
         return readFromFile(ToolsConstants.TOOLS_SOURCE_ROOT + file);
     }
diff --git a/src/tools/utils/ToolsConstants.java b/src/tools/utils/ToolsConstants.java
index 30cb0f413..e36ade989 100644
--- a/src/tools/utils/ToolsConstants.java
+++ b/src/tools/utils/ToolsConstants.java
@@ -10,6 +10,8 @@ public final class ToolsConstants {
 
     public static final String MAIN_SOURCE_ROOT = "src/main/java/";
 
+    public static final String MAIN_RESOURCES_ROOT = "src/main/resources/";
+
     public static final String TOOLS_SOURCE_ROOT = "src/tools/";
 
     public static final String DOCS_FOLDER = TOOLS_SOURCE_ROOT + "docs/";