diff options
author | 2019-06-14 20:33:12 -0700 | |
---|---|---|
committer | 2019-06-14 21:08:22 -0700 | |
commit | acee1bfb6ecb1df0f21f06d1444dd2d7c06f9819 (patch) | |
tree | 6a8381f327fd902b6d0992c0f4deedec8bd0c039 | |
parent | Snekbox: redirect stderr to stdout (diff) |
Snekbox: provide more descriptive messages for failures
Uses the process's return code to determine an appropriate message.
Furthermore, the signal's name is returned if applicable.
* Log process's return code
* Edit cog docstring
-rw-r--r-- | bot/cogs/snekbox.py | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/bot/cogs/snekbox.py b/bot/cogs/snekbox.py index 909479f4f..a01348f3a 100644 --- a/bot/cogs/snekbox.py +++ b/bot/cogs/snekbox.py @@ -3,6 +3,7 @@ import logging import random import re import textwrap +from signal import Signals from typing import Optional, Tuple from discord import Colour, Embed @@ -55,7 +56,7 @@ BYPASS_ROLES = (Roles.owner, Roles.admin, Roles.moderator, Roles.helpers) class Snekbox: """ - Safe evaluation using Snekbox + Safe evaluation of Python code using Snekbox """ def __init__(self, bot: Bot): @@ -104,6 +105,31 @@ class Snekbox: code = textwrap.indent(code, " ") return CODE_TEMPLATE.replace("{CODE}", code) + @staticmethod + def get_results_message(results: dict) -> Tuple[str, str]: + """Return a user-friendly message and error corresponding to the process's return code.""" + stderr, returncode = results["stderr"], results["returncode"] + msg = f"Your eval job has completed with return code {returncode}" + error = "" + + if returncode is None: + msg = "Your eval job has failed" + error = stderr.strip() + elif returncode == 128 + Signals.SIGKILL: + msg = "Your eval job timed out or ran out of memory" + elif returncode == 255: + msg = "Your eval job has failed" + error = "A fatal NsJail error occurred" + else: + # Try to append signal's name if one exists + try: + name = Signals(returncode - 128).name + msg = f"{msg} ({name})" + except ValueError: + pass + + return msg, error + async def format_output(self, output: str) -> Tuple[str, Optional[str]]: """ Format the output and return a tuple of the formatted output and a URL to the full output. @@ -145,9 +171,13 @@ class Snekbox: if truncated: paste_link = await self.upload_output(original_output) - return output.strip(), paste_link + output = output.strip() + if not output: + output = "[No output]" - @command(name='eval', aliases=('e',)) + return output, paste_link + + @command(name="eval", aliases=("e",)) @guild_only() @in_channel(Channels.bot, bypass_roles=BYPASS_ROLES) async def eval_command(self, ctx: Context, *, code: str = None): @@ -178,13 +208,14 @@ class Snekbox: try: async with ctx.typing(): results = await self.post_eval(code) - output, paste_link = await self.format_output(results["stdout"]) - - if not output: - output = "[No output]" + msg, error = self.get_results_message(results) - msg = f"{ctx.author.mention} Your eval job has completed.\n\n```py\n{output}\n```" + if error: + output, paste_link = error, None + else: + output, paste_link = await self.format_output(results["stdout"]) + msg = f"{ctx.author.mention} {msg}.\n\n```py\n{output}\n```" if paste_link: msg = f"{msg}\nFull output: {paste_link}" @@ -192,6 +223,11 @@ class Snekbox: self.bot.loop.create_task( wait_for_deletion(response, user_ids=(ctx.author.id,), client=ctx.bot) ) + + log.info( + f"{ctx.author.name}#{ctx.author.discriminator}'s job had a return code of " + f"{results['returncode']}" + ) finally: del self.jobs[ctx.author.id] |