From d68c73799b4c77685637f865e7a62b3b59c7a58a Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 11 Jan 2017 21:09:17 +0100 Subject: [PATCH] #1055 Grouping and sorting of text messages (PR #198) * Initial grouping of messages_en.yml (thanks to input by @Twonox) * Change MessageFileVerifier to only do verification - no writing * Create classes for sorting and grouping messages as per the messages_en file --- .../fr/xephi/authme/message/MessageKey.java | 5 + src/main/resources/messages/messages_en.yml | 117 +++++++++------- .../tools/messages/MessageFileComments.java | 13 ++ .../tools/messages/MessageFileElement.java | 20 +++ .../messages/MessageFileElementMerger.java | 132 ++++++++++++++++++ .../messages/MessageFileElementReader.java | 78 +++++++++++ .../java/tools/messages/MessageFileEntry.java | 85 +++++++++++ .../tools/messages/MessageFileVerifier.java | 94 +------------ src/test/java/tools/messages/MissingKey.java | 37 ----- .../tools/messages/VerifyMessagesTask.java | 76 +++++----- 10 files changed, 443 insertions(+), 214 deletions(-) create mode 100644 src/test/java/tools/messages/MessageFileComments.java create mode 100644 src/test/java/tools/messages/MessageFileElement.java create mode 100644 src/test/java/tools/messages/MessageFileElementMerger.java create mode 100644 src/test/java/tools/messages/MessageFileElementReader.java create mode 100644 src/test/java/tools/messages/MessageFileEntry.java delete mode 100644 src/test/java/tools/messages/MissingKey.java diff --git a/src/main/java/fr/xephi/authme/message/MessageKey.java b/src/main/java/fr/xephi/authme/message/MessageKey.java index 1e6b338f1..6cc57480f 100644 --- a/src/main/java/fr/xephi/authme/message/MessageKey.java +++ b/src/main/java/fr/xephi/authme/message/MessageKey.java @@ -252,4 +252,9 @@ public enum MessageKey { public String[] getTags() { return tags; } + + @Override + public String toString() { + return key; + } } diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml index 0d6e789e7..85b18b9b3 100644 --- a/src/main/resources/messages/messages_en.yml +++ b/src/main/resources/messages/messages_en.yml @@ -1,49 +1,73 @@ -denied_command: '&cIn order to use this command you must be authenticated!' -same_ip_online: 'A player with the same IP is already in game!' -denied_chat: '&cIn order to chat you must be authenticated!' -kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -unknown_user: '&cThis user isn''t registered!' -unsafe_spawn: '&cYour quit location was unsafe, you have been teleported to the world''s spawnpoint.' -not_logged_in: '&cYou''re not logged in!' -usage_log: '&cUsage: /login ' -wrong_pwd: '&cWrong password!' -unregistered: '&cSuccessfully unregistered!' -reg_disabled: '&cIn-game registration is disabled!' -valid_session: '&2Logged-in due to Session Reconnection.' -login: '&2Successful login!' -vb_nonActiv: '&cYour account isn''t activated yet, please check your emails!' -user_regged: '&cYou already have registered this username!' -usage_reg: '&cUsage: /register ' -max_reg: '&cYou have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection!' -no_perm: '&4You don''t have the permission to perform this action!' -error: '&4An unexpected error occurred, please contact an administrator!' -login_msg: '&cPlease, login with the command "/login "' +# Registration reg_msg: '&3Please, register to the server with the command "/register "' -usage_unreg: '&cUsage: /unregister ' -pwd_changed: '&2Password changed successfully!' +usage_reg: '&cUsage: /register ' +reg_only: '&4Only registered users can join the server! Please visit http://example.com to register yourself!' +kicked_admin_registered: 'An admin just registered you; please log in again' +registered: '&2Successfully registered!' +reg_disabled: '&cIn-game registration is disabled!' +user_regged: '&cYou already have registered this username!' + +# Password errors on registration password_error: '&cPasswords didn''t match, check them again!' password_error_nick: '&cYou can''t use your name as password, please choose another one...' password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -invalid_session: '&cYour IP has been changed and your session data has expired!' -reg_only: '&4Only registered users can join the server! Please visit http://example.com to register yourself!' -logged_in: '&cYou''re already logged in!' -logout: '&2Logged-out successfully!' -same_nick: '&4The same username is already playing on the server!' -registered: '&2Successfully registered!' pass_len: '&cYour password is too short or too long! Please try with another one!' -reload: '&2Configuration and database have been reloaded correctly!' + +# Login +usage_log: '&cUsage: /login ' +wrong_pwd: '&cWrong password!' +login: '&2Successful login!' +login_msg: '&cPlease, login with the command "/login "' timeout: '&4Login timeout exceeded, you have been kicked from the server, please try again!' + +# Errors +unknown_user: '&cThis user isn''t registered!' +denied_command: '&cIn order to use this command you must be authenticated!' +denied_chat: '&cIn order to chat you must be authenticated!' +not_logged_in: '&cYou''re not logged in!' +tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +max_reg: '&cYou have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection!' +no_perm: '&4You don''t have the permission to perform this action!' +error: '&4An unexpected error occurred, please contact an administrator!' +unsafe_spawn: '&cYour quit location was unsafe, you have been teleported to the world''s spawnpoint.' +kick_forvip: '&3A VIP player has joined the server when it was full!' + +# AntiBot +kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled after %m minutes!' + +# Other messages +unregistered: '&cSuccessfully unregistered!' +accounts_owned_self: 'You own %count accounts:' +accounts_owned_other: 'The player %name has %count accounts:' +two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +recovery_code_sent: 'A recovery code to reset your password has been sent to your email.' +recovery_code_incorrect: 'The recovery code is not correct! Use /email recovery [email] to generate a new one' +vb_nonActiv: '&cYour account isn''t activated yet, please check your emails!' +usage_unreg: '&cUsage: /unregister ' +pwd_changed: '&2Password changed successfully!' +logged_in: '&cYou''re already logged in!' +logout: '&2Logged out successfully!' +reload: '&2Configuration and database have been reloaded correctly!' usage_changepassword: '&cUsage: /changepassword ' + +# Session messages +invalid_session: '&cYour IP has been changed and your session data has expired!' +valid_session: '&2Logged-in due to Session Reconnection.' + +# Error messages when joining name_len: '&4Your username is either too short or too long!' regex: '&4Your username contains illegal characters. Allowed chars: REG_EX' -add_email: '&3Please add your email to your account with the command "/email add "' -recovery_email: '&3Forgot your password? Please use the command "/email recovery "' -usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' -wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' -valid_captcha: '&2Captcha code solved correctly!' -kick_forvip: '&3A VIP player has joined the server when it was full!' +country_banned: '&4Your country is banned from this server!' +not_owner_error: 'You are not the owner of this account. Please choose another name!' kick_fullserver: '&4The server is full, try again later!' +same_nick: '&4The same username is already playing on the server!' +invalid_name_case: 'You should join using username %valid, not %invalid.' +same_ip_online: 'A player with the same IP is already in game!' + +# Email usage_email_add: '&cUsage: /email add ' usage_email_change: '&cUsage: /email change ' usage_email_recovery: '&cUsage: /email recovery ' @@ -56,19 +80,14 @@ email_changed: '&2Email address changed correctly!' email_send: '&2Recovery email sent successfully! Please check your email inbox!' email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' email_show: '&2Your current email address is: &f%email' -show_no_email: '&2You currently don''t have email address associated with this account.' -country_banned: '&4Your country is banned from this server!' -antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' -antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled after %m minutes!' -email_already_used: '&4The email address is already being used' -two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -not_owner_error: 'You are not the owner of this account. Please choose another name!' -invalid_name_case: 'You should join using username %valid, not %invalid.' -tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' -accounts_owned_self: 'You own %count accounts:' -accounts_owned_other: 'The player %name has %count accounts:' -kicked_admin_registered: 'An admin just registered you; please log in again' incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.' +email_already_used: '&4The email address is already being used' email_send_failure: 'The email could not be sent. Please contact an administrator.' -recovery_code_sent: 'A recovery code to reset your password has been sent to your email.' -recovery_code_incorrect: 'The recovery code is not correct! Use /email recovery [email] to generate a new one' +show_no_email: '&2You currently don''t have email address associated with this account.' +add_email: '&3Please add your email to your account with the command "/email add "' +recovery_email: '&3Forgot your password? Please use the command "/email recovery "' + +# Captcha +usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' +wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' +valid_captcha: '&2Captcha code solved correctly!' diff --git a/src/test/java/tools/messages/MessageFileComments.java b/src/test/java/tools/messages/MessageFileComments.java new file mode 100644 index 000000000..eaa5d5eed --- /dev/null +++ b/src/test/java/tools/messages/MessageFileComments.java @@ -0,0 +1,13 @@ +package tools.messages; + +import java.util.List; + +/** + * Represents a section of one or more consecutive comment lines in a file. + */ +public class MessageFileComments extends MessageFileElement { + + public MessageFileComments(List lines) { + super(lines); + } +} diff --git a/src/test/java/tools/messages/MessageFileElement.java b/src/test/java/tools/messages/MessageFileElement.java new file mode 100644 index 000000000..775d7f80e --- /dev/null +++ b/src/test/java/tools/messages/MessageFileElement.java @@ -0,0 +1,20 @@ +package tools.messages; + +import java.util.Collections; +import java.util.List; + +/** + * An element (a logical unit) in a messages file. + */ +public abstract class MessageFileElement { + + private final List lines; + + protected MessageFileElement(List lines) { + this.lines = Collections.unmodifiableList(lines); + } + + public List getLines() { + return lines; + } +} diff --git a/src/test/java/tools/messages/MessageFileElementMerger.java b/src/test/java/tools/messages/MessageFileElementMerger.java new file mode 100644 index 000000000..ca5720d3d --- /dev/null +++ b/src/test/java/tools/messages/MessageFileElementMerger.java @@ -0,0 +1,132 @@ +package tools.messages; + +import fr.xephi.authme.message.MessageKey; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Creates the same order of message file elements as the given default message elements, + * using the local file's own elements as much as possible and filling in elements from the + * default messages file where necessary. + *

+ * The current implementation (of this merger and of the {@link MessageFileElementReader reader}) + * has the following limitations: + *

    + *
  • It assumes that new comments are only ever added to the bottom of the default file.
  • + *
  • If a file only has a partial number of the comments present in the default messages file, + * the file's comments will be moved to the top. This most likely adds the comment above the + * wrong group of messages.
  • + *
  • Assumes that the text for a message only takes one line.
  • + *
  • Ignores the last comment section of a file if it is not followed by any message entry.
  • + *
+ */ +public class MessageFileElementMerger { + + /** Ordered list of comments in the messages file. */ + private final List comments; + /** List of message entries by corresponding MessageKey. */ + private final Map entries; + /** + * Ordered list of file elements of the default file. The entries of the (non-default) messages + * file are based on this. + */ + private final List defaultFileElements; + /** Missing tags in message entries. */ + private final Map> missingTags; + /** Counter for encountered comment elements. */ + private int commentsCounter = 0; + + private MessageFileElementMerger(List defaultFileElements, + List comments, + Map entries, + Map> missingTags) { + this.defaultFileElements = defaultFileElements; + this.comments = comments; + this.entries = entries; + this.missingTags = missingTags; + } + + /** + * Returns a list of file elements that follow the order and type of the provided default file elements. + * In other words, using the list of default file elements as template and fallback, it returns the provided + * file elements in the same order and fills in default file elements if an equivalent in {@code fileElements} + * is not present. + * + * @param fileElements file elements to sort and merge + * @param defaultFileElements file elements of the default file to base the operation on + * @param missingTags list of missing tags per message key + * @return ordered and complete list of file elements + */ + public static List mergeElements(List fileElements, + List defaultFileElements, + Map> missingTags) { + List comments = filteredStream(fileElements, MessageFileComments.class) + .collect(Collectors.toList()); + Map entries = filteredStream(fileElements, MessageFileEntry.class) + .collect(Collectors.toMap(MessageFileEntry::getMessageKey, Function.identity(), (e1, e2) -> e1)); + + MessageFileElementMerger merger = new MessageFileElementMerger( + defaultFileElements, comments, entries, missingTags); + return merger.mergeElements(); + } + + private List mergeElements() { + List mergedElements = new ArrayList<>(defaultFileElements.size()); + for (MessageFileElement element : defaultFileElements) { + if (element instanceof MessageFileComments) { + mergedElements.add(getCommentsEntry((MessageFileComments) element)); + } else if (element instanceof MessageFileEntry) { + mergedElements.add(getEntryForDefaultMessageEntry((MessageFileEntry) element)); + } else { + throw new IllegalStateException("Found element of unknown subtype '" + element.getClass() + "'"); + } + } + return mergedElements; + } + + private MessageFileComments getCommentsEntry(MessageFileComments defaultComments) { + if (comments.size() > commentsCounter) { + MessageFileComments localComments = comments.get(commentsCounter); + ++commentsCounter; + return localComments; + } + return defaultComments; + } + + private MessageFileElement getEntryForDefaultMessageEntry(MessageFileEntry entry) { + MessageKey messageKey = entry.getMessageKey(); + if (messageKey == null) { + throw new IllegalStateException("Default message file should not have unknown entries, but " + + " entry with lines '" + entry.getLines() + "' has message key = null"); + } + + MessageFileEntry localEntry = entries.get(messageKey); + if (localEntry == null) { + return entry.convertToMissingEntryComment(); + } + + Collection absentTags = missingTags.get(messageKey); + return absentTags == null + ? localEntry + : localEntry.convertToEntryWithMissingTagsComment(absentTags); + } + + /** + * Creates a stream of the entries in {@code collection} with only the elements which are of type {@code clazz}. + * + * @param collection the collection to stream over + * @param clazz the class to restrict the elements to + * @param

the collection type (parent) + * @param the type to restrict to (child) + * @return stream over all elements of the given type + */ + private static Stream filteredStream(Collection

collection, Class clazz) { + return collection.stream().filter(clazz::isInstance).map(clazz::cast); + } +} diff --git a/src/test/java/tools/messages/MessageFileElementReader.java b/src/test/java/tools/messages/MessageFileElementReader.java new file mode 100644 index 000000000..0546356a5 --- /dev/null +++ b/src/test/java/tools/messages/MessageFileElementReader.java @@ -0,0 +1,78 @@ +package tools.messages; + +import tools.utils.FileIoUtils; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Reads a messages file and returns the lines as corresponding {@link MessageFileElement} objects. + * + * @see MessageFileElementMerger + */ +public class MessageFileElementReader { + + private final List elements = new ArrayList<>(); + + private MessageFileElementReader() { + } + + /** + * Returns the message files as separate {@link MessageFileElement elements}. + * + * @param file the file to read + * @return the file's elements + */ + public static List readFileIntoElements(File file) { + checkArgument(file.exists(), "Template file '" + file + "' must exist"); + + MessageFileElementReader reader = new MessageFileElementReader(); + reader.loadElements(file.toPath()); + return reader.elements; + } + + private void loadElements(Path path) { + List currentCommentSection = new ArrayList<>(10); + for (String line : FileIoUtils.readLinesFromFile(path)) { + if (isTodoComment(line)) { + continue; + } + + if (isCommentLine(line)) { + currentCommentSection.add(line); + } else if (MessageFileEntry.isMessageEntry(line)) { + if (!currentCommentSection.isEmpty()) { + processTempCommentsList(currentCommentSection); + } + elements.add(new MessageFileEntry(line)); + } else { + throw new IllegalStateException("Could not match line '" + line + "' to any type"); + } + } + } + + /** + * Creates a message file comments element for one or more read comment lines. Does not add + * a comments element if the read lines are only empty lines. + * + * @param comments the read comment lines + */ + private void processTempCommentsList(List comments) { + if (comments.stream().anyMatch(c -> !c.trim().isEmpty())) { + elements.add(new MessageFileComments(new ArrayList<>(comments))); + } + comments.clear(); + } + + private static boolean isCommentLine(String line) { + return line.trim().isEmpty() || line.trim().startsWith("#"); + } + + private static boolean isTodoComment(String line) { + return line.startsWith("# TODO "); + } +} diff --git a/src/test/java/tools/messages/MessageFileEntry.java b/src/test/java/tools/messages/MessageFileEntry.java new file mode 100644 index 000000000..788e0b6d3 --- /dev/null +++ b/src/test/java/tools/messages/MessageFileEntry.java @@ -0,0 +1,85 @@ +package tools.messages; + +import fr.xephi.authme.message.MessageKey; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static java.util.Collections.singletonList; + +/** + * Entry in a message file for a message key. + */ +public class MessageFileEntry extends MessageFileElement { + + private static final Pattern MESSAGE_ENTRY_REGEX = Pattern.compile("([a-zA-Z_-]+): .*"); + private final MessageKey messageKey; + + public MessageFileEntry(String line) { + this(singletonList(line), extractMessageKey(line)); + } + + private MessageFileEntry(List lines, MessageKey messageKey) { + super(lines); + this.messageKey = messageKey; + } + + public static boolean isMessageEntry(String line) { + return MESSAGE_ENTRY_REGEX.matcher(line).matches(); + } + + public MessageKey getMessageKey() { + return messageKey; + } + + /** + * Based on this entry, creates a comments element indicating that this message is missing. + * + * @return comments element based on this message element + */ + public MessageFileComments convertToMissingEntryComment() { + List comments = getLines().stream().map(l -> "# TODO " + l).collect(Collectors.toList()); + return new MessageFileComments(comments); + } + + /** + * Creates an adapted message file entry object with a comment for missing tags. + * + * @param missingTags the tags missing in the message + * @return message file entry with verification comment + */ + public MessageFileEntry convertToEntryWithMissingTagsComment(Collection missingTags) { + List lines = new ArrayList<>(getLines().size() + 1); + lines.add("# TODO: Missing tags " + String.join(", ", missingTags)); + lines.addAll(getLines()); + return new MessageFileEntry(lines, messageKey); + } + + /** + * Returns the {@link MessageKey} this entry is for. Returns {@code null} if the message key could not be matched. + * + * @param line the line to process + * @return the associated message key, or {@code null} if no match was found + */ + private static MessageKey extractMessageKey(String line) { + Matcher matcher = MESSAGE_ENTRY_REGEX.matcher(line); + if (matcher.find()) { + String key = matcher.group(1); + return fromKey(key); + } + throw new IllegalStateException("Could not extract message key from line '" + line + "'"); + } + + private static MessageKey fromKey(String key) { + for (MessageKey messageKey : MessageKey.values()) { + if (messageKey.getKey().equals(key)) { + return messageKey; + } + } + return null; + } +} diff --git a/src/test/java/tools/messages/MessageFileVerifier.java b/src/test/java/tools/messages/MessageFileVerifier.java index b151228c1..058799054 100644 --- a/src/test/java/tools/messages/MessageFileVerifier.java +++ b/src/test/java/tools/messages/MessageFileVerifier.java @@ -1,21 +1,14 @@ package tools.messages; import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; -import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import fr.xephi.authme.message.MessageKey; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import tools.utils.FileIoUtils; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -26,8 +19,8 @@ public class MessageFileVerifier { private final File messagesFile; private final Set unknownKeys = new HashSet<>(); - private final List missingKeys = new ArrayList<>(); - private final Multimap missingTags = HashMultimap.create(); + private final Set missingKeys = new HashSet<>(); + private final Multimap missingTags = HashMultimap.create(); /** * Create a verifier that verifies the given messages file. @@ -56,16 +49,16 @@ public class MessageFileVerifier { * * @return The list of missing keys in the file */ - public List getMissingKeys() { + public Set getMissingKeys() { return missingKeys; } /** * Return the collection of tags the message key defines that aren't present in the read line. * - * @return Collection of missing tags per message key. Key = message key, value = missing tag. + * @return Collection of missing tags per message key */ - public Multimap getMissingTags() { + public Multimap getMissingTags() { return missingTags; } @@ -78,7 +71,7 @@ public class MessageFileVerifier { if (configuration.isString(key)) { checkTagsInMessage(messageKey, configuration.getString(key)); } else { - missingKeys.add(new MissingKey(key)); + missingKeys.add(messageKey); } } @@ -93,84 +86,11 @@ public class MessageFileVerifier { private void checkTagsInMessage(MessageKey messageKey, String message) { for (String tag : messageKey.getTags()) { if (!message.contains(tag)) { - missingTags.put(messageKey.getKey(), tag); + missingTags.put(messageKey, tag); } } } - /** - * Add missing keys to the file with the provided default (English) message. - * - * @param defaultMessages The collection of default messages - */ - public void addMissingKeys(FileConfiguration defaultMessages) { - final List fileLines = FileIoUtils.readLinesFromFile(messagesFile.toPath()); - - List keysToAdd = new ArrayList<>(); - for (MissingKey entry : missingKeys) { - final String key = entry.getKey(); - - if (!entry.getWasAdded() && defaultMessages.get(key) != null) { - keysToAdd.add(entry); - } - } - - // Add missing keys as comments to the bottom of the file - for (MissingKey keyToAdd : keysToAdd) { - final String key = keyToAdd.getKey(); - int indexOfComment = Iterables.indexOf(fileLines, isCommentFor(key)); - if (indexOfComment != -1) { - // Comment for keyToAdd already exists, so remove it since we're going to add it - fileLines.remove(indexOfComment); - } - String comment = commentForKey(key) + "'" + - defaultMessages.getString(key).replace("'", "''") + "'"; - fileLines.add(comment); - keyToAdd.setWasAdded(true); - } - - // Add a comment above messages missing a tag - for (Map.Entry> entry : missingTags.asMap().entrySet()) { - final String key = entry.getKey(); - addCommentForMissingTags(fileLines, key, entry.getValue()); - } - - FileIoUtils.writeToFile(messagesFile.toPath(), String.join("\n", fileLines)); - } - - /** - * Add a comment above a message to note the tags the message is missing. Removes - * any similar comment that may already be above the message. - * - * @param fileLines The lines of the file (to modify) - * @param key The key of the message - * @param tags The missing tags - */ - private void addCommentForMissingTags(List fileLines, final String key, Collection tags) { - int indexForComment = Iterables.indexOf(fileLines, isCommentFor(key)); - if (indexForComment == -1) { - indexForComment = Iterables.indexOf(fileLines, input -> input.startsWith(key + ": ")); - if (indexForComment == -1) { - System.err.println("Error adding comment for key '" + key + "': couldn't find entry in file lines"); - return; - } - } else { - fileLines.remove(indexForComment); - } - - String tagWord = tags.size() > 1 ? "tags" : "tag"; - fileLines.add(indexForComment, commentForKey(key) - + String.format("Missing %s %s", tagWord, String.join(", ", tags))); - } - - private static String commentForKey(String key) { - return String.format("# TODO %s: ", key); - } - - private static Predicate isCommentFor(final String key) { - return input -> input.startsWith(commentForKey(key)); - } - private static boolean messageKeyExists(String key) { for (MessageKey messageKey : MessageKey.values()) { if (messageKey.getKey().equals(key)) { diff --git a/src/test/java/tools/messages/MissingKey.java b/src/test/java/tools/messages/MissingKey.java deleted file mode 100644 index 667768012..000000000 --- a/src/test/java/tools/messages/MissingKey.java +++ /dev/null @@ -1,37 +0,0 @@ -package tools.messages; - -/** - * Missing message key in a file. - */ -public class MissingKey { - - private final String key; - private boolean wasAdded; - - public MissingKey(String key) { - this.key = key; - } - - /** - * @return the message key that is missing - */ - public String getKey() { - return key; - } - - public void setWasAdded(boolean wasAdded) { - this.wasAdded = wasAdded; - } - - /** - * @return true if a comment was added to the file, false otherwise - */ - public boolean getWasAdded() { - return wasAdded; - } - - @Override - public String toString() { - return key; - } -} diff --git a/src/test/java/tools/messages/VerifyMessagesTask.java b/src/test/java/tools/messages/VerifyMessagesTask.java index 661ff9d86..b7e1efe1b 100644 --- a/src/test/java/tools/messages/VerifyMessagesTask.java +++ b/src/test/java/tools/messages/VerifyMessagesTask.java @@ -1,9 +1,9 @@ package tools.messages; import com.google.common.collect.Multimap; +import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.util.StringUtils; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; +import tools.utils.FileIoUtils; import tools.utils.ToolTask; import tools.utils.ToolsConstants; @@ -54,9 +54,9 @@ public final class VerifyMessagesTask implements ToolTask { messageFiles = Collections.singletonList(customFile); } - FileConfiguration defaultMessages = null; + List defaultFileElements = null; if (addMissingKeys) { - defaultMessages = YamlConfiguration.loadConfiguration(new File(DEFAULT_MESSAGES_FILE)); + defaultFileElements = MessageFileElementReader.readFileIntoElements(new File(DEFAULT_MESSAGES_FILE)); } // Verify the given files @@ -64,9 +64,10 @@ public final class VerifyMessagesTask implements ToolTask { System.out.println("Verifying '" + file.getName() + "'"); MessageFileVerifier verifier = new MessageFileVerifier(file); if (addMissingKeys) { - verifyFileAndAddKeys(verifier, defaultMessages); + outputVerificationResults(verifier); + updateMessagesFile(file, verifier, defaultFileElements); } else { - verifyFile(verifier); + outputVerificationResults(verifier); } } @@ -75,8 +76,13 @@ public final class VerifyMessagesTask implements ToolTask { } } - private static void verifyFile(MessageFileVerifier verifier) { - List missingKeys = verifier.getMissingKeys(); + /** + * Outputs the verification results to the console. + * + * @param verifier the verifier whose results should be output + */ + private static void outputVerificationResults(MessageFileVerifier verifier) { + Set missingKeys = verifier.getMissingKeys(); if (!missingKeys.isEmpty()) { System.out.println(" Missing keys: " + missingKeys); } @@ -86,44 +92,32 @@ public final class VerifyMessagesTask implements ToolTask { System.out.println(" Unknown keys: " + unknownKeys); } - Multimap missingTags = verifier.getMissingTags(); - for (Map.Entry entry : missingTags.entries()) { - System.out.println(" Missing tag '" + entry.getValue() + "' in entry with key '" + entry.getKey() + "'"); + Multimap missingTags = verifier.getMissingTags(); + for (Map.Entry entry : missingTags.entries()) { + System.out.println(" Missing tag '" + entry.getValue() + "' in entry '" + entry.getKey() + "'"); } } - public static void verifyFileAndAddKeys(MessageFileVerifier verifier, FileConfiguration defaultMessages) { - List missingKeys = verifier.getMissingKeys(); - if (!missingKeys.isEmpty() || !verifier.getMissingTags().isEmpty()) { - verifier.addMissingKeys(defaultMessages); - List addedKeys = getMissingKeysWithAdded(missingKeys, true); - System.out.println(" Added missing keys " + addedKeys); - - List unsuccessfulKeys = getMissingKeysWithAdded(missingKeys, false); - if (!unsuccessfulKeys.isEmpty()) { - System.err.println(" Warning! Could not add all missing keys (problem with loading " + - "default messages?)"); - System.err.println(" Could not add keys " + unsuccessfulKeys); - } - } - - Set unknownKeys = verifier.getUnknownKeys(); - if (!unknownKeys.isEmpty()) { - System.out.println(" Unknown keys: " + unknownKeys); - } - - Multimap missingTags = verifier.getMissingTags(); - for (Map.Entry entry : missingTags.entries()) { - System.out.println(" Missing tag '" + entry.getValue() + "' in entry with key '" + entry.getKey() + "'"); - } + /** + * Updates a messages file to have the same order as the default file and to contain all + * failed verifications as comments. + * + * @param file the file to update + * @param verifier the verifier whose results should be used + * @param defaultFileElements default file elements to base the new file structure on + */ + private static void updateMessagesFile(File file, MessageFileVerifier verifier, + List defaultFileElements) { + List messageFileElements = MessageFileElementReader.readFileIntoElements(file); + String newMessageFileContents = MessageFileElementMerger + .mergeElements(messageFileElements, defaultFileElements, verifier.getMissingTags().asMap()) + .stream() + .map(MessageFileElement::getLines) + .flatMap(List::stream) + .collect(Collectors.joining("\n")); + FileIoUtils.writeToFile(file.toPath(), newMessageFileContents + "\n"); } - private static List getMissingKeysWithAdded(List missingKeys, boolean wasAdded) { - return missingKeys.stream() - .filter(e -> e.getWasAdded() == wasAdded) - .map(MissingKey::getKey) - .collect(Collectors.toList()); - } private static List getMessagesFiles() { File[] files = listFilesOrThrow(new File(MESSAGES_FOLDER));