diff --git a/buildtools/deploy.sh b/buildtools/deploy.sh index 945e59a..499f18f 100755 --- a/buildtools/deploy.sh +++ b/buildtools/deploy.sh @@ -7,7 +7,14 @@ VERSION=$2 pushd $DEPLOY_DIR +file=$VERSIONS/NurseBot$VERSION.jar + +if test ! -f $file; then + echo "Version not found." + exit 1 +fi + unlink NurseBot.jar -ln $VERSIONS/NurseBot$VERSION.jar NurseBot.jar +ln $file NurseBot.jar popd diff --git a/buildtools/update.sh b/buildtools/update.sh index d25bdc7..676beb1 100755 --- a/buildtools/update.sh +++ b/buildtools/update.sh @@ -1,4 +1,10 @@ #!/bin/bash git checkout production +if test ! $? = 0; then + exit 1 +fi git pull origin production +if test ! $? = 0; then + exit 2 +fi diff --git a/src/asylum/nursebot/exceptions/WhatTheFuckExecption.java b/src/asylum/nursebot/exceptions/WhatTheFuckExecption.java new file mode 100644 index 0000000..1cf0880 --- /dev/null +++ b/src/asylum/nursebot/exceptions/WhatTheFuckExecption.java @@ -0,0 +1,5 @@ +package asylum.nursebot.exceptions; + +public class WhatTheFuckExecption extends RuntimeException { + +} diff --git a/src/asylum/nursebot/executor/CallbackContext.java b/src/asylum/nursebot/executor/CallbackContext.java new file mode 100644 index 0000000..c6dc08c --- /dev/null +++ b/src/asylum/nursebot/executor/CallbackContext.java @@ -0,0 +1,21 @@ +package asylum.nursebot.executor; + +import java.util.HashMap; + +import asylum.nursebot.exceptions.WhatTheFuckExecption; + +public class CallbackContext extends HashMap, Object>{ + private static final long serialVersionUID = 1988125468800948893L; + + public void put(Object object) { + put(object.getClass(), object); + } + + @SuppressWarnings("unchecked") + public T get(Class clazz) { + Object obj = ((HashMap, Object>) this).get(clazz); + if (!(clazz.isInstance(obj))) + throw new WhatTheFuckExecption(); + return (T) obj; + } +} diff --git a/src/asylum/nursebot/executor/ErrorCallback.java b/src/asylum/nursebot/executor/ErrorCallback.java new file mode 100644 index 0000000..10c6adb --- /dev/null +++ b/src/asylum/nursebot/executor/ErrorCallback.java @@ -0,0 +1,7 @@ +package asylum.nursebot.executor; + +import java.util.function.BiConsumer; + +public interface ErrorCallback extends BiConsumer{ + +} diff --git a/src/asylum/nursebot/executor/ExecuterData.java b/src/asylum/nursebot/executor/ExecuterData.java new file mode 100644 index 0000000..dd8d9b0 --- /dev/null +++ b/src/asylum/nursebot/executor/ExecuterData.java @@ -0,0 +1,30 @@ +package asylum.nursebot.executor; + +import java.io.InputStream; +import java.io.OutputStream; + +public class ExecuterData { + + private InputStream stdout; + private InputStream stderr; + private OutputStream stdin; + + public ExecuterData(InputStream stdout, OutputStream stdin, InputStream stderr) { + this.stdout = stdout; + this.stderr = stderr; + this.stdin = stdin; + } + + public InputStream getStdout() { + return stdout; + } + + public InputStream getStderr() { + return stderr; + } + + public OutputStream getStdin() { + return stdin; + } + +} diff --git a/src/asylum/nursebot/executor/ExitCallback.java b/src/asylum/nursebot/executor/ExitCallback.java new file mode 100644 index 0000000..10966f5 --- /dev/null +++ b/src/asylum/nursebot/executor/ExitCallback.java @@ -0,0 +1,7 @@ +package asylum.nursebot.executor; + +import java.util.function.BiConsumer; + +public interface ExitCallback extends BiConsumer{ + +} diff --git a/src/asylum/nursebot/executor/ExitCode.java b/src/asylum/nursebot/executor/ExitCode.java new file mode 100644 index 0000000..446dc6d --- /dev/null +++ b/src/asylum/nursebot/executor/ExitCode.java @@ -0,0 +1,14 @@ +package asylum.nursebot.executor; + +public class ExitCode { + private int value; + + public int getValue() { + return value; + } + + public ExitCode(int value) { + super(); + this.value = value; + } +} diff --git a/src/asylum/nursebot/executor/ExternalExecuter.java b/src/asylum/nursebot/executor/ExternalExecuter.java new file mode 100644 index 0000000..8c70884 --- /dev/null +++ b/src/asylum/nursebot/executor/ExternalExecuter.java @@ -0,0 +1,75 @@ +package asylum.nursebot.executor; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + + +public class ExternalExecuter implements Runnable { + + private ExitCallback exit; + private ErrorCallback error; + private CallbackContext context; + + private String program; + private List arguments; + private File directory; + + private InputStream stdout; + private OutputStream stdin; + private InputStream stderr; + + public ExternalExecuter(String program, List arguments, File directory, ExitCallback exit, ErrorCallback error, CallbackContext context) { + + this.program = program; + if (arguments != null) + this.arguments = arguments; + else + this.arguments = new LinkedList<>(); + this.exit = exit; + this.directory = directory; + this.context = context; + + this.exit = exit; + this.error = error; + } + + @Override + public void run() { + try { + List args = new LinkedList<>(arguments); + args.add(0, program); + + ProcessBuilder builder = new ProcessBuilder(args); + builder.directory(directory); + Process process = builder.start(); + + this.stdout = process.getInputStream(); + this.stderr = process.getErrorStream(); + this.stdin = process.getOutputStream(); + + context.put(ExecuterData.class, new ExecuterData(stdout, stdin, stderr)); + + int exitCode = process.waitFor(); + if (exit != null) + exit.accept(new ExitCode(exitCode), context); + } catch (Exception e) { + error.accept(e, context); + } + } + + public InputStream getStdout() { + return stdout; + } + + public OutputStream getStdin() { + return stdin; + } + + public InputStream getStderr() { + return stderr; + } +} diff --git a/src/asylum/nursebot/modules/Builder.java b/src/asylum/nursebot/modules/Builder.java new file mode 100644 index 0000000..8710d94 --- /dev/null +++ b/src/asylum/nursebot/modules/Builder.java @@ -0,0 +1,186 @@ +package asylum.nursebot.modules; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import org.telegram.telegrambots.api.objects.Message; +import org.telegram.telegrambots.exceptions.TelegramApiException; + +import com.google.inject.Inject; +import java.util.Scanner; + +import asylum.nursebot.NurseNoakes; +import asylum.nursebot.Sender; +import asylum.nursebot.commands.CommandCategory; +import asylum.nursebot.commands.CommandHandler; +import asylum.nursebot.commands.CommandInterpreter; +import asylum.nursebot.executor.CallbackContext; +import asylum.nursebot.executor.ErrorCallback; +import asylum.nursebot.executor.ExecuterData; +import asylum.nursebot.executor.ExitCallback; +import asylum.nursebot.executor.ExternalExecuter; +import asylum.nursebot.loader.AutoModule; +import asylum.nursebot.objects.Locality; +import asylum.nursebot.objects.Module; +import asylum.nursebot.objects.ModuleType; +import asylum.nursebot.objects.Permission; +import asylum.nursebot.objects.Visibility; + +import static asylum.nursebot.utils.ExceptionIgnorer.ignore; + +@AutoModule(load=true) +public class Builder implements Module { + private final String PREFIX = "/buildtools/"; + private final String RUNDIR = System.getProperty("user.dir"); + + + @Inject + private CommandHandler commandHandler; + + private CommandCategory category; + + @Override + public String getName() { + return "Builder"; + } + + @Override + public ModuleType getType() { + return new ModuleType() + .set(ModuleType.COMMAND_MODULE) + .set(ModuleType.META_MODULE); + } + + public Builder() { + category = new CommandCategory("Builder"); + } + + private void startScript(String scriptname, List arguments, ExitCallback exit, ErrorCallback error, CallbackContext context) { + ExternalExecuter executer = new ExternalExecuter(scriptname, arguments, new File(RUNDIR + PREFIX), exit, error, context); + new Thread(executer).start(); + } + + private CallbackContext getContext(Message message, Sender sender) { + CallbackContext context = new CallbackContext(); + context.put(message); + context.put(sender); + return context; + } + + private void update(CallbackContext context) { + startScript("./update.sh", null, (e, c) -> { + String msg; + if (e.getValue() != 0) { + msg = "Das Aktualisieren ist fehlgeschlagen."; + } else { + msg = "Das Aktualisieren war erfolgreich."; + } + ignore(TelegramApiException.class, () -> { + c.get(Sender.class).reply(msg, c.get(Message.class)); + }); + }, (e, c) -> { + e.printStackTrace(); + }, context); + } + + private void build(CallbackContext context) { + startScript("./build.sh", Arrays.asList(RUNDIR + "/"), (e, c) -> { + String msg; + if (e.getValue() != 0) { + msg = "Der Build ist fehlgeschlagen mit " + e.getValue() + "."; + } else { + msg = "Der Build war erfolgreich."; + } + ignore(TelegramApiException.class, () -> { + c.get(Sender.class).reply(msg, c.get(Message.class)); + }); + }, (e, c) -> { + e.printStackTrace(); + }, context); + } + + private void deploy(CallbackContext context, String version) { + startScript("./deploy.sh", Arrays.asList(RUNDIR + "/", version), (e, c) -> { + String msg; + if (e.getValue() != 0) { + msg = "Der Deploy ist fehlgeschlagen."; + } else { + msg = "Der Deploy war erfolgreich."; + } + ignore(TelegramApiException.class, () -> { + c.get(Sender.class).reply(msg, c.get(Message.class)); + }); + }, (e, c) -> { + e.printStackTrace(); + }, context); + } + + private void displayVersion(CallbackContext context) { + startScript("./versions.sh", Arrays.asList(RUNDIR + "/"), (e, c) -> { + Scanner scanner = new Scanner(c.get(ExecuterData.class).getStdout()); + StringBuilder builder = new StringBuilder(); + + builder.append("Versions:\n"); + + while(scanner.hasNextLine()) + builder.append("- ").append(scanner.nextLine()).append("\n"); + + ignore(TelegramApiException.class, () -> { + c.get(Sender.class).reply(builder.toString(), c.get(Message.class)); + }); + + scanner.close(); + }, (e, c) -> { + e.printStackTrace(); + }, context); + } + + @Override + public void init() { + commandHandler.add(new CommandInterpreter(this) + .setName("versions") + .setInfo("zeigt aktuell verfügbare Versionen an") + .setCategory(category) + .setLocality(Locality.EVERYWHERE) + .setPermission(Permission.ANY) + .setVisibility(Visibility.PUBLIC) + .setAction(c -> { + if (!NurseNoakes.BOT_ADMIN_USERNAMES.contains(c.getMessage().getFrom().getUserName())) { + c.getSender().reply("Das dürfen nur Bot-Admins.", c.getMessage()); + return; + } + + displayVersion(getContext(c.getMessage(), c.getSender())); + })); + + commandHandler.add(new CommandInterpreter(this) + .setName("update") + .setInfo("bringt den git Klon auf den neuesten Stand und wechselt auf den development branch") + .setCategory(category) + .setLocality(Locality.EVERYWHERE) + .setPermission(Permission.ANY) + .setVisibility(Visibility.PUBLIC) + .setAction(c -> { + if (!NurseNoakes.BOT_ADMIN_USERNAMES.contains(c.getMessage().getFrom().getUserName())) { + c.getSender().reply("Das dürfen nur Bot-Admins.", c.getMessage()); + return; + } + + update(getContext(c.getMessage(), c.getSender())); + })); + } + + @Override + public void activate() { + } + + @Override + public void deactivate() { + } + + @Override + public void shutdown() { + } + +} diff --git a/src/asylum/nursebot/objects/ModuleType.java b/src/asylum/nursebot/objects/ModuleType.java index a33ef8a..7915911 100644 --- a/src/asylum/nursebot/objects/ModuleType.java +++ b/src/asylum/nursebot/objects/ModuleType.java @@ -1,9 +1,10 @@ package asylum.nursebot.objects; public class ModuleType { - public static int COMMAND_MODULE = 1 << 0; - public static int SEMANTIC_MODULE = 1 << 1; + public static final int COMMAND_MODULE = 1 << 0; + public static final int SEMANTIC_MODULE = 1 << 1; public static final int TEST_MODULE = 1 << 3; + public static final int META_MODULE = 1 << 4; private int value = 0; @@ -24,6 +25,8 @@ public class ModuleType { return 'S'; case 3: return 'T'; + case 4: + return 'M'; default: return '?'; } diff --git a/src/asylum/nursebot/utils/ExceptionIgnorer.java b/src/asylum/nursebot/utils/ExceptionIgnorer.java new file mode 100644 index 0000000..1cf4559 --- /dev/null +++ b/src/asylum/nursebot/utils/ExceptionIgnorer.java @@ -0,0 +1,21 @@ +package asylum.nursebot.utils; + +public class ExceptionIgnorer { + + public static void ignore(Class clazz, ToBeIgnored action) { + ignore(clazz, true, action); + } + + public static void ignore(Class clazz, boolean stackTrace, ToBeIgnored action) { + try { + action.action(); + } catch(Exception e) { + if (clazz.isInstance(e)) { + if (stackTrace) + e.printStackTrace(); + } else { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/asylum/nursebot/utils/ToBeIgnored.java b/src/asylum/nursebot/utils/ToBeIgnored.java new file mode 100644 index 0000000..62e7892 --- /dev/null +++ b/src/asylum/nursebot/utils/ToBeIgnored.java @@ -0,0 +1,5 @@ +package asylum.nursebot.utils; + +public interface ToBeIgnored { + void action() throws Exception; +}