#963 Create tool task to generate plugin.yml

- Create task that generates commands/permissions section of plugin.yml
- Change CommandInitializer to return a List instead of Set (preserve insertion order)
- Merge CommandSyntaxHelper into CommandUtils
This commit is contained in:
ljacqu 2016-10-23 12:17:37 +02:00
parent 1867617dbb
commit d09964f1cb
18 changed files with 527 additions and 337 deletions

View File

@ -1,6 +1,6 @@
package fr.xephi.authme.command;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableList;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.command.executable.authme.AccountsCommand;
import fr.xephi.authme.command.executable.authme.AuthMeCommand;
@ -41,14 +41,13 @@ import fr.xephi.authme.permission.PlayerPermission;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* Initializes all available AuthMe commands.
*/
public class CommandInitializer {
private Set<CommandDescription> commands;
private List<CommandDescription> commands;
public CommandInitializer() {
buildCommands();
@ -59,7 +58,7 @@ public class CommandInitializer {
*
* @return the command descriptions
*/
public Set<CommandDescription> getCommands() {
public List<CommandDescription> getCommands() {
return commands;
}
@ -67,7 +66,7 @@ public class CommandInitializer {
// Register the base AuthMe Reloaded command
final CommandDescription AUTHME_BASE = CommandDescription.builder()
.labels("authme")
.description("Main command")
.description("AuthMe op commands")
.detailedDescription("The main AuthMeReloaded command. The root for all admin commands.")
.executableCommand(AuthMeCommand.class)
.register();
@ -324,7 +323,7 @@ public class CommandInitializer {
final CommandDescription REGISTER_BASE = CommandDescription.builder()
.parent(null)
.labels("register", "reg")
.description("Registration command")
.description("Register an account")
.detailedDescription("Command to register using AuthMeReloaded.")
.withArgument("password", "Password", true)
.withArgument("verifyPassword", "Verify password", true)
@ -336,7 +335,7 @@ public class CommandInitializer {
CommandDescription UNREGISTER_BASE = CommandDescription.builder()
.parent(null)
.labels("unregister", "unreg")
.description("Unregistration Command")
.description("Unregister an account")
.detailedDescription("Command to unregister using AuthMeReloaded.")
.withArgument("password", "Password", false)
.permission(PlayerPermission.UNREGISTER)
@ -347,10 +346,10 @@ public class CommandInitializer {
final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
.parent(null)
.labels("changepassword", "changepass", "cp")
.description("Change password Command")
.description("Change password of an account")
.detailedDescription("Command to change your password using AuthMeReloaded.")
.withArgument("oldPassword", "Old Password", false)
.withArgument("newPassword", "New Password.", false)
.withArgument("oldPassword", "Old password", false)
.withArgument("newPassword", "New password", false)
.permission(PlayerPermission.CHANGE_PASSWORD)
.executableCommand(ChangePasswordCommand.class)
.register();
@ -359,8 +358,8 @@ public class CommandInitializer {
CommandDescription EMAIL_BASE = CommandDescription.builder()
.parent(null)
.labels("email")
.description("Email command")
.detailedDescription("The AuthMeReloaded Email command base.")
.description("Add email or recover password")
.detailedDescription("The AuthMeReloaded email command base.")
.executableCommand(EmailBaseCommand.class)
.register();
@ -401,7 +400,7 @@ public class CommandInitializer {
CommandDescription.builder()
.parent(EMAIL_BASE)
.labels("recover", "recovery", "recoveremail", "recovermail")
.description("Recover password using Email")
.description("Recover password using email")
.detailedDescription("Recover your account using an Email address by sending a mail containing " +
"a new password.")
.withArgument("email", "Email address", false)
@ -421,7 +420,7 @@ public class CommandInitializer {
.executableCommand(CaptchaCommand.class)
.register();
Set<CommandDescription> baseCommands = ImmutableSet.of(
List<CommandDescription> baseCommands = ImmutableList.of(
AUTHME_BASE,
LOGIN_BASE,
LOGOUT_BASE,

View File

@ -8,6 +8,7 @@ import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -26,7 +27,7 @@ public class CommandMapper {
*/
private static final Class<? extends ExecutableCommand> HELP_COMMAND_CLASS = HelpCommand.class;
private final Set<CommandDescription> baseCommands;
private final Collection<CommandDescription> baseCommands;
private final PermissionsManager permissionsManager;
@Inject

View File

@ -1,9 +1,11 @@
package fr.xephi.authme.command;
import com.google.common.collect.Lists;
import org.bukkit.ChatColor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public final class CommandUtils {
@ -34,6 +36,14 @@ public final class CommandUtils {
return sb.toString();
}
/**
* Constructs a hierarchical list of commands for the given command. The commands are in order:
* the parents of the given command precede the provided command. For example, given the command
* for {@code /authme register}, a list with {@code [{authme}, {authme register}]} is returned.
*
* @param command the command to build a parent list for
* @return the parent list
*/
public static List<CommandDescription> constructParentList(CommandDescription command) {
List<CommandDescription> commands = new ArrayList<>();
CommandDescription currentCommand = command;
@ -43,4 +53,35 @@ public final class CommandUtils {
}
return Lists.reverse(commands);
}
public static String buildSyntax(CommandDescription command) {
String arguments = command.getArguments().stream()
.map(arg -> formatArgument(arg))
.collect(Collectors.joining(" "));
return (constructCommandPath(command) + " " + arguments).trim();
}
public static String buildSyntax(CommandDescription command, List<String> correctLabels) {
String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW;
for (int i = 1; i < correctLabels.size(); ++i) {
commandSyntax += " " + correctLabels.get(i);
}
for (CommandArgumentDescription argument : command.getArguments()) {
commandSyntax += " " + formatArgument(argument);
}
return commandSyntax;
}
/**
* Format a command argument with the proper type of brackets.
*
* @param argument the argument to format
* @return the formatted argument
*/
public static String formatArgument(CommandArgumentDescription argument) {
if (argument.isOptional()) {
return "[" + argument.getName() + "]";
}
return "<" + argument.getName() + ">";
}
}

View File

@ -1,36 +0,0 @@
package fr.xephi.authme.command.help;
import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription;
import org.bukkit.ChatColor;
import java.util.List;
/**
* Helper class for displaying the syntax of a command properly to a user.
*/
final class CommandSyntaxHelper {
private CommandSyntaxHelper() {
}
public static String getSyntax(CommandDescription command, List<String> correctLabels) {
String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW;
for (int i = 1; i < correctLabels.size(); ++i) {
commandSyntax += " " + correctLabels.get(i);
}
for (CommandArgumentDescription argument : command.getArguments()) {
commandSyntax += " " + formatArgument(argument);
}
return commandSyntax;
}
/** Format a command argument with the proper type of brackets. */
private static String formatArgument(CommandArgumentDescription argument) {
if (argument.isOptional()) {
return "[" + argument.getName() + "]";
}
return "<" + argument.getName() + ">";
}
}

View File

@ -80,7 +80,7 @@ public class HelpProvider implements Reloadable {
if (hasFlag(SHOW_COMMAND, options)) {
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.COMMAND) + ": "
+ CommandSyntaxHelper.getSyntax(command, correctLabels));
+ CommandUtils.buildSyntax(command, correctLabels));
}
if (hasFlag(SHOW_DESCRIPTION, options)) {
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(SHORT_DESCRIPTION) + ": "
@ -194,7 +194,7 @@ public class HelpProvider implements Reloadable {
// Create a list of alternatives
for (String label : command.getLabels()) {
if (!label.equalsIgnoreCase(usedLabel)) {
lines.add(" " + CommandSyntaxHelper.getSyntax(command, commandLabelsFn.apply(label)));
lines.add(" " + CommandUtils.buildSyntax(command, commandLabelsFn.apply(label)));
}
}
}

View File

@ -15,191 +15,197 @@ softdepend:
- EssentialsSpawn
- ProtocolLib
commands:
authme:
description: AuthMe op commands
usage: '/authme reload|register playername password|changepassword playername password|unregister playername|version|converter'
register:
description: Register an account
usage: /register <password> <confirmpassword>
aliases: [reg]
login:
description: Login command
usage: /login <password>
aliases: [l,log]
changepassword:
description: Change password of an account
usage: /changepassword <oldPassword> <newPassword>
aliases: [cp,changepass]
logout:
description: Logout
usage: /logout
unregister:
description: Unregister your account
usage: /unregister <password>
aliases: [unreg]
email:
description: Add Email or recover password
usage: '/email add your@email.com your@email.com|change oldEmail newEmail|recovery your@email.com'
captcha:
description: Captcha command
usage: /captcha <code>
authme:
description: AuthMe op commands
usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages
login:
description: Login command
usage: /login <password>
aliases:
- l
- log
logout:
description: Logout command
usage: /logout
register:
description: Register an account
usage: /register [password] [verifyPassword]
aliases:
- reg
unregister:
description: Unregister an account
usage: /unregister <password>
aliases:
- unreg
changepassword:
description: Change password of an account
usage: /changepassword <oldPassword> <newPassword>
aliases:
- changepass
- cp
email:
description: Add email or recover password
usage: /email show|add|change|recover
captcha:
description: Captcha Command
usage: /captcha <captcha>
permissions:
authme.admin.*:
description: Give access to all admin commands.
children:
authme.admin.accounts: true
authme.admin.antibotmessages: true
authme.admin.changemail: true
authme.admin.changepassword: true
authme.admin.converter: true
authme.admin.firstspawn: true
authme.admin.forcelogin: true
authme.admin.getemail: true
authme.admin.getip: true
authme.admin.lastlogin: true
authme.admin.purge: true
authme.admin.purgebannedplayers: true
authme.admin.purgelastpos: true
authme.admin.register: true
authme.admin.reload: true
authme.admin.setfirstspawn: true
authme.admin.setspawn: true
authme.admin.spawn: true
authme.admin.switchantibot: true
authme.admin.unregister: true
authme.admin.updatemessages: true
authme.admin.register:
description: Administrator command to register a new user.
default: op
authme.admin.unregister:
description: Administrator command to unregister an existing user.
default: op
authme.admin.forcelogin:
description: Administrator command to force-login an existing user.
default: op
authme.admin.changepassword:
description: Administrator command to change the password of a user.
default: op
authme.admin.lastlogin:
description: Administrator command to see the last login date and time of a user.
default: op
authme.admin.accounts:
description: Administrator command to see all accounts associated with a user.
default: op
authme.admin.getemail:
description: Administrator command to get the email address of a user, if set.
default: op
authme.admin.changemail:
description: Administrator command to set or change the email address of a user.
default: op
authme.admin.getip:
description: Administrator command to get the last known IP of a user.
default: op
authme.admin.spawn:
description: Administrator command to teleport to the AuthMe spawn.
default: op
authme.admin.setspawn:
description: Administrator command to set the AuthMe spawn.
default: op
authme.admin.firstspawn:
description: Administrator command to teleport to the first AuthMe spawn.
default: op
authme.admin.setfirstspawn:
description: Administrator command to set the first AuthMe spawn.
default: op
authme.admin.purge:
description: Administrator command to purge old user data.
default: op
authme.admin.purgelastpos:
description: Administrator command to purge the last position of a user.
default: op
authme.admin.purgebannedplayers:
description: Administrator command to purge all data associated with banned players.
default: op
authme.admin.seeotheraccounts:
description: Permission for user to see other accounts.
default: op
authme.admin.switchantibot:
description: Administrator command to toggle the AntiBot protection status.
default: op
authme.admin.converter:
description: Administrator command to convert old or other data to AuthMe data.
default: op
authme.admin.reload:
description: Administrator command to reload the plugin configuration.
default: op
authme.admin.antibotmessages:
description: Permission to see Antibot messages.
default: op
authme.admin.updatemessages:
description: Permission to use the update messages command.
default: op
authme.player.*:
description: Permission to use all player (non-admin) commands.
children:
authme.player.canbeforced: true
authme.player.captcha: true
authme.player.changepassword: true
authme.player.email.add: true
authme.player.email.change: true
authme.player.email.recover: true
authme.player.login: true
authme.player.logout: true
authme.player.register: true
authme.player.unregister: true
authme.player.seeownaccounts: true
authme.player.email:
description: Gives access to player email commands
default: false
children:
authme.player.email.add: true
authme.player.email.change: true
authme.player.email.recover: true
authme.player.login:
description: Command permission to login.
default: true
authme.player.logout:
description: Command permission to logout.
default: true
authme.player.register:
description: Command permission to register.
default: true
authme.player.unregister:
description: Command permission to unregister.
default: true
authme.player.changepassword:
description: Command permission to change the password.
default: true
authme.player.email.add:
description: Command permission to add an email address.
default: true
authme.player.email.change:
description: Command permission to change the email address.
default: true
authme.player.email.recover:
description: Command permission to recover an account using its email address.
default: true
authme.player.captcha:
description: Command permission to use captcha.
default: true
authme.player.canbeforced:
description: Permission for users a login can be forced to.
default: true
authme.player.seeownaccounts:
description: Permission to use to see own other accounts.
default: true
authme.vip:
description: Allow vip slot when the server is full
default: op
authme.bypassantibot:
description: Bypass the AntiBot check
default: op
authme.allowmultipleaccounts:
description: Allow more accounts for same ip
default: op
authme.bypassforcesurvival:
description: Bypass all ForceSurvival features
default: op
authme.bypasspurge:
description: Permission to bypass the purging process
default: false
authme.admin.*:
description: Gives access to all admin commands
children:
authme.admin.accounts: true
authme.admin.antibotmessages: true
authme.admin.changemail: true
authme.admin.changepassword: true
authme.admin.converter: true
authme.admin.firstspawn: true
authme.admin.forcelogin: true
authme.admin.getemail: true
authme.admin.getip: true
authme.admin.lastlogin: true
authme.admin.purge: true
authme.admin.purgebannedplayers: true
authme.admin.purgelastpos: true
authme.admin.register: true
authme.admin.reload: true
authme.admin.seeotheraccounts: true
authme.admin.setfirstspawn: true
authme.admin.setspawn: true
authme.admin.spawn: true
authme.admin.switchantibot: true
authme.admin.unregister: true
authme.admin.updatemessages: true
authme.admin.accounts:
description: Administrator command to see all accounts associated with a user.
default: op
authme.admin.antibotmessages:
description: Permission to see Antibot messages.
default: op
authme.admin.changemail:
description: Administrator command to set or change the email address of a user.
default: op
authme.admin.changepassword:
description: Administrator command to change the password of a user.
default: op
authme.admin.converter:
description: Administrator command to convert old or other data to AuthMe data.
default: op
authme.admin.firstspawn:
description: Administrator command to teleport to the first AuthMe spawn.
default: op
authme.admin.forcelogin:
description: Administrator command to force-login an existing user.
default: op
authme.admin.getemail:
description: Administrator command to get the email address of a user, if set.
default: op
authme.admin.getip:
description: Administrator command to get the last known IP of a user.
default: op
authme.admin.lastlogin:
description: Administrator command to see the last login date and time of a user.
default: op
authme.admin.purge:
description: Administrator command to purge old user data.
default: op
authme.admin.purgebannedplayers:
description: Administrator command to purge all data associated with banned players.
default: op
authme.admin.purgelastpos:
description: Administrator command to purge the last position of a user.
default: op
authme.admin.register:
description: Administrator command to register a new user.
default: op
authme.admin.reload:
description: Administrator command to reload the plugin configuration.
default: op
authme.admin.seeotheraccounts:
description: Permission to see the other accounts of the players that log in.
default: op
authme.admin.setfirstspawn:
description: Administrator command to set the first AuthMe spawn.
default: op
authme.admin.setspawn:
description: Administrator command to set the AuthMe spawn.
default: op
authme.admin.spawn:
description: Administrator command to teleport to the AuthMe spawn.
default: op
authme.admin.switchantibot:
description: Administrator command to toggle the AntiBot protection status.
default: op
authme.admin.unregister:
description: Administrator command to unregister an existing user.
default: op
authme.admin.updatemessages:
description: Permission to use the update messages command.
default: op
authme.allowmultipleaccounts:
description: Permission to be able to register multiple accounts.
default: op
authme.bypassantibot:
description: Permission node to bypass AntiBot protection.
default: op
authme.bypassforcesurvival:
description: Permission for users to bypass force-survival mode.
default: op
authme.bypasspurge:
description: Permission to bypass the purging process.
default: false
authme.player.*:
description: Gives access to all player commands
children:
authme.player.canbeforced: true
authme.player.captcha: true
authme.player.changepassword: true
authme.player.email.add: true
authme.player.email.change: true
authme.player.email.recover: true
authme.player.login: true
authme.player.logout: true
authme.player.register: true
authme.player.seeownaccounts: true
authme.player.unregister: true
authme.player.canbeforced:
description: Permission for users a login can be forced to.
default: true
authme.player.captcha:
description: Command permission to use captcha.
default: true
authme.player.changepassword:
description: Command permission to change the password.
default: true
authme.player.email:
description: Gives access to all email commands
children:
authme.player.email.add: true
authme.player.email.change: true
authme.player.email.recover: true
authme.player.email.add:
description: Command permission to add an email address.
default: true
authme.player.email.change:
description: Command permission to change the email address.
default: true
authme.player.email.recover:
description: Command permission to recover an account using its email address.
default: true
authme.player.login:
description: Command permission to login.
default: true
authme.player.logout:
description: Command permission to logout.
default: true
authme.player.register:
description: Command permission to register.
default: true
authme.player.seeownaccounts:
description: Permission to use to see own other accounts.
default: true
authme.player.unregister:
description: Command permission to unregister.
default: true
authme.vip:
description: Permission node to identify VIP users.
default: op

View File

@ -18,6 +18,7 @@ import java.util.regex.Pattern;
import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@ -32,7 +33,7 @@ public class CommandInitializerTest {
*/
private static int MAX_ALLOWED_DEPTH = 1;
private static Set<CommandDescription> commands;
private static Collection<CommandDescription> commands;
@BeforeClass
public static void initializeCommandCollection() {
@ -46,7 +47,7 @@ public class CommandInitializerTest {
// It obviously doesn't make sense to test much of the concrete data
// that is being initialized; we just want to guarantee with this test
// that data is indeed being initialized and we take a few "probes"
assertThat(commands.size(), equalTo(8));
assertThat(commands, hasSize(8));
assertThat(commandsIncludeLabel(commands, "authme"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "register"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "help"), equalTo(false));

View File

@ -39,7 +39,7 @@ import static org.mockito.Mockito.mock;
@RunWith(DelayedInjectionRunner.class)
public class CommandMapperTest {
private static Set<CommandDescription> commands;
private static List<CommandDescription> commands;
@InjectDelayed
private CommandMapper mapper;

View File

@ -1,8 +1,15 @@
package fr.xephi.authme.command;
import fr.xephi.authme.TestHelper;
import org.bukkit.ChatColor;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
@ -11,6 +18,13 @@ import static org.junit.Assert.assertThat;
*/
public class CommandUtilsTest {
private static Collection<CommandDescription> commands;
@BeforeClass
public static void setUpTestCommands() {
commands = TestCommandsUtil.generateCommands();
}
@Test
public void shouldReturnCommandPath() {
// given
@ -79,6 +93,46 @@ public class CommandUtilsTest {
TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandUtils.class);
}
@Test
public void shouldFormatSimpleArgument() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme");
List<String> labels = Collections.singletonList("authme");
// when
String result = CommandUtils.buildSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW));
}
@Test
public void shouldFormatCommandWithMultipleArguments() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register");
List<String> labels = Arrays.asList("authme", "reg");
// when
String result = CommandUtils.buildSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg <password> <confirmation>"));
}
@Test
public void shouldFormatCommandWithOptionalArgument() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email");
List<String> labels = Collections.singletonList("email");
// when
String result = CommandUtils.buildSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]"));
}
private static void checkArgumentCount(CommandDescription command, int expectedMin, int expectedMax) {
assertThat(CommandUtils.getMinNumberOfArguments(command), equalTo(expectedMin));

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.command;
import com.google.common.collect.ImmutableList;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionNode;
@ -8,9 +9,7 @@ import org.bukkit.command.CommandSender;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@ -27,7 +26,7 @@ public final class TestCommandsUtil {
*
* @return The generated commands
*/
public static Set<CommandDescription> generateCommands() {
public static List<CommandDescription> generateCommands() {
// Register /authme
CommandDescription authMeBase = createCommand(null, null, singletonList("authme"), ExecutableCommand.class);
// Register /authme login <password>
@ -48,7 +47,7 @@ public final class TestCommandsUtil {
CommandDescription unregisterBase = createCommand(AdminPermission.UNREGISTER, null,
asList("unregister", "unreg"), TestUnregisterCommand.class, newArgument("player", false));
return newHashSet(authMeBase, emailBase, unregisterBase);
return ImmutableList.of(authMeBase, emailBase, unregisterBase);
}
/**

View File

@ -1,76 +0,0 @@
package fr.xephi.authme.command.help;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.TestCommandsUtil;
import org.bukkit.ChatColor;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Test for {@link CommandSyntaxHelper}.
*/
public class CommandSyntaxHelperTest {
private static Set<CommandDescription> commands;
@BeforeClass
public static void setUpTestCommands() {
commands = TestCommandsUtil.generateCommands();
}
@Test
public void shouldFormatSimpleArgument() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme");
List<String> labels = Collections.singletonList("authme");
// when
String result = CommandSyntaxHelper.getSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW));
}
@Test
public void shouldFormatCommandWithMultipleArguments() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register");
List<String> labels = Arrays.asList("authme", "reg");
// when
String result = CommandSyntaxHelper.getSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg <password> <confirmation>"));
}
@Test
public void shouldFormatCommandWithOptionalArgument() {
// given
CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email");
List<String> labels = Collections.singletonList("email");
// when
String result = CommandSyntaxHelper.getSyntax(command, labels);
// then
assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]"));
}
@Test
public void shouldHaveHiddenConstructor() {
// given / when / then
TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandSyntaxHelper.class);
}
}

View File

@ -9,8 +9,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
@ -78,7 +78,7 @@ public class HelpMessagesConsistencyTest {
* @return the CommandDescription object for the {@code /authme register} command.
*/
private static CommandDescription getAuthMeRegisterDescription() {
Set<CommandDescription> commands = new CommandInitializer().getCommands();
Collection<CommandDescription> commands = new CommandInitializer().getCommands();
List<CommandDescription> children = commands.stream()
.filter(command -> command.getLabels().contains("authme"))

View File

@ -12,7 +12,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import java.util.Set;
import java.util.Collection;
import java.util.function.Function;
import static fr.xephi.authme.TestHelper.getJarFile;
@ -31,7 +31,7 @@ import static org.mockito.Matchers.any;
public class HelpMessagesServiceTest {
private static final String TEST_FILE = "/fr/xephi/authme/command/help/help_test.yml";
private static final Set<CommandDescription> COMMANDS = TestCommandsUtil.generateCommands();
private static final Collection<CommandDescription> COMMANDS = TestCommandsUtil.generateCommands();
@InjectDelayed
private HelpMessagesService helpMessagesService;

View File

@ -20,9 +20,9 @@ import org.mockito.Mock;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel;
@ -53,7 +53,7 @@ import static org.mockito.Mockito.verify;
@RunWith(DelayedInjectionRunner.class)
public class HelpProviderTest {
private static Set<CommandDescription> commands;
private static Collection<CommandDescription> commands;
@InjectDelayed
private HelpProvider helpProvider;

View File

@ -26,7 +26,7 @@ public class PermissionConsistencyTest {
/** All classes defining permission nodes. */
private static final Set<Class<? extends PermissionNode>> PERMISSION_CLASSES = ImmutableSet
.<Class<? extends PermissionNode>>of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class);
.of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class);
/** Wildcard permissions (present in plugin.yml but not in the codebase). */
private static final Set<String> PLUGIN_YML_PERMISSIONS_WILDCARDS =

View File

@ -13,7 +13,6 @@ import tools.utils.ToolsConstants;
import java.util.Collection;
import java.util.Scanner;
import java.util.Set;
public class CommandPageCreater implements AutoToolTask {
@ -32,7 +31,7 @@ public class CommandPageCreater implements AutoToolTask {
@Override
public void executeDefault() {
CommandInitializer commandInitializer = new CommandInitializer();
final Set<CommandDescription> baseCommands = commandInitializer.getCommands();
final Collection<CommandDescription> baseCommands = commandInitializer.getCommands();
NestedTagValue commandTags = new NestedTagValue();
addCommandsInfo(commandTags, baseCommands);

View File

@ -7,10 +7,12 @@ import tools.utils.ToolsConstants;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Gatherer to generate up-to-date lists of the AuthMe permission nodes.
@ -27,6 +29,11 @@ public class PermissionNodesGatherer {
+ "(.*?)\\s+\\*/" // Capture everything until we encounter '*/'
+ "\\s+([A-Z_]+)\\("); // Match the enum name (e.g. 'LOGIN'), until before the first '('
/**
* List of all enum classes that implement the {@link PermissionNode} interface.
*/
private List<Class<? extends PermissionNode>> permissionClasses;
/**
* Return a sorted collection of all permission nodes, including its JavaDoc description.
*
@ -39,14 +46,27 @@ public class PermissionNodesGatherer {
result.put("authme.player.*", "Permission to use all player (non-admin) commands.");
result.put("authme.player.email", "Grants all email permissions.");
new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, "")
.collectClasses(PermissionNode.class)
.stream()
.filter(Class::isEnum)
.forEach(clz -> addDescriptionsForClass((Class<T>) clz, result));
getPermissionClasses().forEach(clz -> addDescriptionsForClass((Class<T>) clz, result));
return result;
}
/**
* Return all enum classes implementing the PermissionNode interface.
*
* @return all permission node enums
*/
public List<Class<? extends PermissionNode>> getPermissionClasses() {
if (permissionClasses == null) {
ClassCollector classCollector = new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, "");
permissionClasses = classCollector
.collectClasses(PermissionNode.class)
.stream()
.filter(Class::isEnum)
.collect(Collectors.toList());
}
return permissionClasses;
}
private <T extends Enum<T> & PermissionNode> void addDescriptionsForClass(Class<T> clazz,
Map<String, String> descriptions) {
String classSource = getSourceForClass(clazz);

View File

@ -0,0 +1,182 @@
package tools.filegeneration;
import com.google.common.collect.ImmutableMap;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandInitializer;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import tools.docs.permissions.PermissionNodesGatherer;
import tools.utils.AutoToolTask;
import tools.utils.FileUtils;
import tools.utils.ToolsConstants;
import java.io.StringReader;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* Generates the command and permission section of plugin.yml.
*/
public class GeneratePluginYml implements AutoToolTask {
private static final String PLUGIN_YML_FILE = ToolsConstants.MAIN_RESOURCES_ROOT + "plugin.yml";
private static final Map<String, String> WILDCARD_PERMISSIONS = ImmutableMap.of(
"authme.player.*", "Gives access to all player commands",
"authme.admin.*", "Gives access to all admin commands",
"authme.player.email", "Gives access to all email commands");
private List<PermissionNode> permissionNodes;
private String pluginYmlStart;
@Override
public void executeDefault() {
FileConfiguration configuration = loadPartialPluginYmlFile();
configuration.set("commands", generateCommands());
configuration.set("permissions", generatePermissions());
FileUtils.writeToFile(PLUGIN_YML_FILE,
pluginYmlStart + "\n" + configuration.saveToString());
}
@Override
public String getTaskName() {
return "generatePluginYml";
}
@Override
public void execute(Scanner scanner) {
executeDefault();
}
/**
* Because some parts above the commands section have placeholders that aren't valid YAML, we need
* to split the contents into an upper part that we ignore and a lower part we load as YAML. When
* saving we prepend the YAML export with the stripped off part of the file again.
*
* @return file configuration with the lower part of the plugin.yml file
*/
private FileConfiguration loadPartialPluginYmlFile() {
List<String> pluginYmlLines = FileUtils.readLinesFromFile(Paths.get(PLUGIN_YML_FILE));
int lineNr = 0;
for (String line : pluginYmlLines) {
if (line.equals("commands:")) {
break;
}
++lineNr;
}
if (lineNr == pluginYmlLines.size()) {
throw new IllegalStateException("Could not find line starting 'commands:' section");
}
pluginYmlStart = String.join("\n", pluginYmlLines.subList(0, lineNr));
String yamlContents = String.join("\n", pluginYmlLines.subList(lineNr, pluginYmlLines.size()));
return YamlConfiguration.loadConfiguration(new StringReader(yamlContents));
}
private static Map<String, Object> generateCommands() {
Collection<CommandDescription> commands = new CommandInitializer().getCommands();
Map<String, Object> entries = new LinkedHashMap<>();
for (CommandDescription command : commands) {
entries.put(command.getLabels().get(0), buildCommandEntry(command));
}
return entries;
}
private Map<String, Object> generatePermissions() {
PermissionNodesGatherer gatherer = new PermissionNodesGatherer();
Map<String, String> permissionDescriptions = gatherer.gatherNodesWithJavaDoc();
permissionNodes = gatherer.getPermissionClasses().stream()
// Note ljacqu 20161023: The compiler fails if we use method references below
.map(clz -> clz.getEnumConstants())
.flatMap((PermissionNode[] nodes) -> Arrays.stream(nodes))
.collect(Collectors.toList());
Map<String, Object> descriptions = new TreeMap<>();
for (PermissionNode node : permissionNodes) {
descriptions.put(node.getNode(), buildPermissionEntry(node, permissionDescriptions.get(node.getNode())));
}
addWildcardPermissions(descriptions);
return descriptions;
}
private void addWildcardPermissions(Map<String, Object> permissions) {
for (Map.Entry<String, String> entry : WILDCARD_PERMISSIONS.entrySet()) {
permissions.put(entry.getKey(),
buildWildcardPermissionEntry(entry.getValue(), gatherChildren(entry.getKey())));
}
}
private Map<String, Boolean> gatherChildren(String parentNode) {
String parentPath = parentNode.replaceAll("\\.\\*$", "");
Map<String, Boolean> children = new TreeMap<>();
for (PermissionNode node : permissionNodes) {
if (node.getNode().startsWith(parentPath)) {
children.put(node.getNode(), Boolean.TRUE);
}
}
return children;
}
private static Map<String, Object> buildCommandEntry(CommandDescription command) {
if (command.getLabels().size() > 1) {
return ImmutableMap.of(
"description", command.getDescription(),
"usage", buildUsage(command),
"aliases", command.getLabels().subList(1, command.getLabels().size()));
} else {
return ImmutableMap.of(
"description", command.getDescription(),
"usage", buildUsage(command));
}
}
private static String buildUsage(CommandDescription command) {
if (!command.getArguments().isEmpty()) {
return CommandUtils.buildSyntax(command);
}
final String commandStart = "/" + command.getLabels().get(0);
String usage = commandStart + " " + command.getChildren()
.stream()
.filter(cmd -> !cmd.getLabels().contains("help"))
.map(cmd -> cmd.getLabels().get(0))
.collect(Collectors.joining("|"));
return usage.trim();
}
private static Map<String, Object> buildPermissionEntry(PermissionNode permissionNode, String description) {
return ImmutableMap.of(
"description", description,
"default", convertDefaultPermission(permissionNode.getDefaultPermission()));
}
private static Map<String, Object> buildWildcardPermissionEntry(String description, Map<String, Boolean> children) {
return ImmutableMap.of(
"description", description,
"children", children);
}
private static Object convertDefaultPermission(DefaultPermission defaultPermission) {
switch (defaultPermission) {
// Returning true/false as booleans will make SnakeYAML avoid using quotes
case ALLOWED: return true;
case NOT_ALLOWED: return false;
case OP_ONLY: return "op";
default:
throw new IllegalArgumentException("Unknown default permission '" + defaultPermission + "'");
}
}
}